I recently developed a simple program designed to take a certain amount of money (in dollars) and determine the least number of coins necessary to fulfill that requirement.
#include <stdio.h>
#include <cs50.h>
int main(void)
{
// prompts for change and assigns variable owed_change that value
float owed_change = -1;
while (owed_change < 0 )
{
printf("How much change is owed?\n");
owed_change = GetFloat();
}
// sets the varialble n_coins to 0
int n_coins = 0;
// repeats until no more change is owed
while (owed_change != 0)
{
/* checks for the biggest coin that can be used and increases
the number of coins by 1 */
if (owed_change >= .25)
{
owed_change -= .25;
n_coins++;
}
else if (owed_change >= .10)
{
owed_change -= .10;
n_coins++;
}
else if (owed_change >= .05)
{
owed_change -= .05;
n_coins++;
}
else
{
owed_change -= .01;
n_coins++;
}
}
printf("%d\n", n_coins);
}
The program works for multiples of .25 but runs forever for any other number. From testing, I have found out that it has something to do with the variable owed_change being subtracted from and coming to the result of -0, which satisfies owed_change != 0. However, from research, I have found out that -0 as a floating point should act as +0. If so, what else have I done wrong?
It would be better, in your case, to work with money as cents and multiply all your values by 100. The reason for this is that floats are not exact values; that would be the reason why your code works for floating point values like 0.25, but not for smaller floating point numbers like 0.1, 0.05, and 0.01. For your purpose, you would be better off using an int value.
Instead of:
0.25$, use 25 cents
0.10$, use 10 cents
0.05$, use 5 cents
0.01$, use 1 cent
Change the data type of owed_change to int from float after making the above changes. That should resolve your problem.
Related
I am trying to do a greedy algorithm for CS50, but for some reason I keep getting errors saying "expression result unused" when trying to divide the total sum of cents by 25, 10, 5, etc. Would someone be able to pinpoint where I am going wrong? Thank you so much in advance.
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
float Change;
int quarters = 25;
int dimes = 10;
int nickels = 5;
int pennies = 1;
int count = 0;
do
{
Change = get_float("Change: ");
}
while (Change < 0);
int cents = round(Change * 100);
while (cents % 25 >= 25)
{
cents/25;
count = count + 1;
}
while (cents % 10 >= 10)
{
cents/10;
count = count + 1;
}
while (cents % 5 >= 5)
{
cents/5;
count = count + 1;
}
while (cents % 1 >= 1)
{
cents/1;
count = count + 1;
}
printf("%d coins", count);
}
Wrong compare
The following is never true. cents % 25, the remainder after division, is always less than 25.
while (cents % 25 >= 25)
Useless code
The below divides by 25 then discards the quotient. #Some programmer dude
cents/25;
Instead in the 25, 10, 5, 1 places
// while (cents % 25 >= 25)
while (cents >= 25)
// cents/25;
cents -= 25;
More efficient code possible. Hint: while loops not needed.
Good to convert input to integers.
Deeper:
int cents = round(Change * 100); produces a float product from Change * 100, then converts to double in calling round(double). Lastly it converts the results to int as part of the assignment.
Could have used roundf(float) and skip the double conversion.
For learner code this is a good start. Note that Change * 100 can causes a rounding error which would show itself in select cases near a half cent. Suggest round(Change * 100.0)
Perhaps use long lround(double x) to expiate the final conversion from double to an integer.
Note that excessively large input causes overflow and undefined behavior.
Just as the error message is telling you: The value you are calculating cents/n isn't going anywhere. I think you are trying to do cents = cents/n.
Also, yourwhile loops are checking the value of cents but you are incrementing the variable count. So you will never exit the loop.
Goal:
Implement a program that calculates the minimum number of coins required to give a user change.
Issue:
Program does not execute properly. I'm fairly sure that my issue is logical in nature, but could also be resultant from my inexperience with proper formatting.
Extra information:
I added a print function to the code to determine where the problem was. "test1" is broadcast, "test2" is not.
I am using some functions local to the cs50.h library:
get_float(); - gets a float value from the user and stores it.
Please do not fix my code for me! I need to learn to do that myself. I just need help finding my logical error or formatting error. Yes, I know that it's not efficient.
Examples of what I'm looking for:
"Your issue is in line X, your values make it so that VARIABLE never reaches 0."
"In C, you can't format '( x < 0 );' - you have to say '(x<0);'."
Code walk-through:
Program obtains 2 float values from user, 'amount' and 'cost'. 'amount' is how much money was given by customer, 'cost' is the cost of the item.
Program finds 'amount - cost' to determine how much change is owed. This value is stored in 'diff'.
Program subtracts 0.25 from 'diff' and adds 1 to variable 'quarter'.
Program subtracts 0.10 from 'diff' and adds 1 to variable 'dime'.
...
Program prints how many Quarters, Dimes, Nickels, Pennies need to be used to give the customer change in the most efficient manner possible.
Assume that only coins can be used.
Code:
#include <stdio.h>
#include <cs50.h>
int main()
{
float cost;
do
{
printf("How much did it cost?\n");
cost = get_float();
}
while (cost < 0);
float amount;
do
{
printf("How much did you pay?\n");
amount = get_float();
}
while (amount < cost);
int quarter = 0;
int dime = 0;
int nickel = 0;
int penny = 0;
float diff = amount - cost;
do
{
while (diff >= 0.25)
{
diff = diff - .25;
quarter++;
}
printf("test1");
while (.10 <= diff < .25)
{
diff = diff - 0.10;
dime++;
}
printf("test2");
while (0.05 <= diff < .10)
{
diff = diff - 0.05;
nickel++;
}
while (0.01 < diff < 0.05)
{
diff = diff - 0.01;
penny++;
}
while (diff == 0.01)
{
penny++;
diff = 0;
}
} // end bracket for do function
while (diff > 0);
if (diff == 0)
{
printf("Your change consists of:\n");
printf("%i quarters.\n", quarter);
printf("%i dimes.\n", dime);
printf("%i nickels.\n", nickel);
printf("%i pennies.\n", penny);
exit(0);
}
if (diff < 0)
{
printf("Your change consists of:\n");
printf("%i quarters.\n", quarter);
printf("%i dimes.\n", dime);
printf("%i nickels.\n", nickel);
printf("%i pennies.\n", penny);
exit(0);
}
} // end bracket for int main
Expected result:
Program works as previously described.
Actual result:
Program does not execute fully. 'test1' is broadcast, 'test2' is not.
First of all, you need to check the accuracy for floating point arithmetic.
That said, statements like
while (.10 <= diff < .25)
does not do what you think they do. Chaining of relational operators are not possible using the approach you used in C.
You need to couple them using && operator, like
while (.10 <= diff && diff < .25) {
The trouble is with comparisons like 0.05 <= diff < .10 which are not the same as 0.05 <= diff && diff < .10 The latter does what you intend, the former compares 0 or 1 to .10. If diff is greater than 0.05, then '0.05 <= diff' evaluates to 1, which is then compared to .10. What you've written is the same as (0.05 <= diff) < .10.
First of all, your loop is eternal.
while (amount < cost); <-- Amount and cost never change. So...
Second of all, you can not write conditions like (1 <= 2 < 3), it does not mean what you think it means. It seperately executes the operators, so you end up with something akin to (1 <= 2) < 3, the first being either a 1 (true) or a 0 (false).
#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.
X is a decimal that enters a bunch of loops that keep subtracting certain decimals from it and c is an integer that increments by one every time an operation happens. Four operations should happen but the last loop terminates early and the c never increments from 3 to 4. The last while loop keeps terminating early?
int main(void) {
float x = 0.41;
int c = 0;
while(x >= 0.25)
{
x-= 0.25;
c++;
}
while(x >= 0.1)
{
x-= 0.1;
c++;
}
while(x >= 0.05)
{
x-= 0.05;
c++;
}
while(x >= 0.01)
{
c++;
x-= 0.01;
}
printf("%i", c);
}
Floats in C are not absolutely precise. They have 23 bits to actually represent the actual value. When you write
float x = 0.41
The actual representation of the value in the float value is slightly different from exactly 0.41, depending on your computer architecture/compiler.
To see for yourself, add the following line to each of your loop blocks:
printf("%d, %.30f\n", c, x);
On my machine, I get
1, 0.159999999999999975575093458247
2, 0.059999999999999970023978335121
3, 0.009999999999999967248420773558
Comparisons with floats in C should be handled with epsilon values for these discrepancies. In your case, you should allow the compared values to have be within a bound of the target value. Something like
#include <math.h>
...
while(fabs(x-0.01f) < 0.000001) //check that x is within a certain range of 0.01
Reference on the topic: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
while(x >= 0.05)
{
x-= 0.05;
c++;
}
while(x >= 0.1)
{
c++;
x-= 0.01;
}
try Switching these to these
while(x >= 0.1)
{
c++;
x-= 0.01;
}
while(x >= 0.05)
{
x-= 0.05;
c++;
}
Exact comparisons don't mix with finite precision. It's precisely the same reason if you represent 1/3 with some number of decimal digits (0.3333333), you'll need to add it to zero four times before it's greater than or equal to one.
This question already has answers here:
Working With Floats and Integers
(7 answers)
Closed 8 years ago.
I have this function:
int change(float c)
{
float coins[] = {0.25, 0.10, 0.05, 0.01};
int count[] = {0, 0, 0, 0};
while(c > (0.00))
{
printf("I entered here\n");
if((c-coins[0]) >= (0.00))
{
c -= coins[0];
count[0]++;
printf("-0.25, c = %.2f\n", c);
}
else if((c-coins[1]) >= (0.00))
{
c -= coins[1];
count[1]++;
printf("-0.10, c = %.2f\n", c);
}
else if((c-coins[2]) >= (0.00))
{
c -= coins[2];
count[2]++;
printf("-0.05, c = %.2f\n", c);
}
else if((c-coins[3]) >= (0.00))
{
c -= coins[3];
count[3]++;
printf("-0.01, c = %.2f\n", c);
}
}
printf("(%d) 25 cents, (%d) 10 cents, (%d) 5 cents, (%d) 1 cents\n",
count[0], count[1], count[2], count[3]);
int total = count[0] + count[1] + count[2] + count[3];
return total;
}
And whenever I try to enter 0.06 or 0.07, or any float number that will cause it to reach the last else if clause (the else if((c-coins[3]) >= (0.00))) it will cause an infinite loop.
Whereas if I enter 0.25, 0.10, 0.05 and their respective perfect multiples, the function goes smoothly. (Because maybe it wont reach the last else if clause).
And so when I debugged (using simple printf techniques), I found out that the variable c still enters the while loop even though it has reached 0.00. On some occasions, it would even reach -0.00 or -0.01 (and this only works if I changed the else if((c-coins[3]) >= (0.00)) to else only).
Example (assuming the else if in the code is already else only):
Input: 0.06
c-0.05, c = 0.01
c-0.01, c = -0.00 **<- WTF**
(0) 25 cents, (0) 10 cents, (1) 5 cents, (1) 1 cents
Total Coins: 2
Someone explain this to me? Am I missing out some rules regarding float numbers here? Or some errors are caused by that last else if clause of mine?
Note: Changing the last else if to else may work but can affect the final answer. Also, changing the while condition to -0.00 or 0.001 doesn't work.
Floating point values (typically) use a binary representation. The only fraction in your coins array that can be represented exactly is 0.25. All the other values will be slightly smaller or larger than the correct value. This means that every arithmetic operation on these values, even simple substraction, will introduce small computation errors that will cause your comparisons and output to be faulty.
The best solution, in my opinion, is to use only integer types and perform all your calculations in cents (hundreds). You can print out the amounts using division and modulo.
int change(int cents)
{
int coins[] = {25, 10, 5, 1};
int count[] = {0, 0, 0, 0};
while(cents > 0)
{
if((c-coins[0]) >= 0)
{
c -= coins[0];
count[0]++;
printf("-0.25, c = %d.%02d\n", c/100, c%100);
}
/* and so on */
You may want to use unsigned or long or both depending on your needs.