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).
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.
One of my C assignments was it to write an approximation of arctan(x) in the language C. The equation which I should base it on is
arctan(x)=\sum {k=0}^{\infty }(-1)^{k} \tfrac{x^{2k+1}}{2k+1}
In addition x is only defined as -1<=x<=1.
Here is my code.
#include <stdio.h>
#include <math.h>
double main(void) {
double x=1;
double k;
double sum;
double sum_old;
int count;
double pw(double y, double n) {
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
} else {
printf("x is not defined. Please choose an x in the intervall [-1, 1]\n");
}
return 0;
}
It seemingly works fine with every value, except value 1 and -1. If x=1, then the output ends with:
...
7207 || 0.78543285189457468
7208 || 0.78536
Whereas the output should look more like this. In this case x=0.5.
25 || 0.46364760900080587
26 || 0.46364760900080587
My result is: 0.46364760900080587
atan(0.500000) is: 0.46364760900080609
My result minus atan(x) atan(x) = -0.00000000000000022
How can I improve my code so that it can run with x=1 and x=-1.
Thanks in advance.
PS: I use my own created pw() function instead of pow(), because I wanted to bybass the restriction of not using pow() as we didn't had that in our lectures yet.
PPS: I'd appreciate any advice as to how to improve my code.
In each iteration, you add (-1)k • x2k+1 / (2k+1), and you stop when there is no change to the sum.
If this were calculated with ideal arithmetic (exact, infinitely precise arithmetic), it would never stop for non-zero x, since you are always changing the sum. When calculating with fixed-precision arithmetic, it stops when the term is so small it does not change the sum because of the limited precision.
When |x| is less than one by any significant amount, this comes quickly because x2k+1 gets smaller. When |x| is one, the term becomes just 1 / (2k+1), which gets smaller very slowly. Not until k is around 253 would the sum stop changing.
You might consider changing your stopping condition to be when sum has not changed from sum_old very much rather than when it has not changed at all.
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
Comparing doubles can be tricky. The conventional way to compare doubles is to test within epsilon. There should be an epsilon value defined somewhere, but for your purposes how many digits are enough to approximate? If you only need like 3 or 4 digits you can instead have
#define EPSILON 0.0001 //make this however precise you need to approximate.
if(x >= (-1) && x <= 1) {
for(k=0; fabs(sum - sum_old) > EPSILON; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
If the issue is that -1,1 iterate too many times either reduce the precision or increase the step per iteration. I am not sure that is what you're asking though, please clarify.
I think the cause of this is for a mathematical reason rather than a programming one.
Away from the little mistakes and adjustments that you should do to your code, putting x = 1 in the infinite series of arctan, is a boundary condition:
In this series, we add a negative value to a positive value then a negative value. This means the sum will be increasing, decreasing, increasing, ... and this will make some difference each iteration. This difference will be smaller until the preciseness of double won't catch it, so the program will stop and give us the value.
But in the sum equation. When we set z = 1 and n goes from 0 to ∞, this will make this term (-1^n) equal to 1 in one time and -1 in the next iteration. Also,
the value of the z-term will be one and the denominator value when n approaches infinity will = ∞ .
So the sum several iterations will be like +1/∞ -1/∞ +1/∞ -1/∞ ... (where ∞ here represents a big number). That way the series will not reach a specific number. This is because z = 1 is a boundary in this equation. And that is causing infinite iterations in your solution without reaching a number.
If you need to calculate arctan(1) I think you should use this formula:
All formulas are from this Wikipedia article.
Here is some modifications that make your code more compact and has less errors:
#include <stdio.h>
#include <math.h>
#define x 0.5 //here x is much easier to change
double pw(double, double); //declaration of the function should be done
int main() { //the default return type of main is int.
double k;
double sum = 0 ; //you should initiate your variables.
double sum_old = 1 ; //=1 only to pass the for condition first time.
//you don't need to define counter here
if(x < -1 || x > 1){
printf("x is not defined. Please choose an x in the interval [-1, 1]\n");
return 0;
}
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
printf("%.0f || %.17lf\n", k, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
return 0;
}
double pw(double y, double n) { //functions should be declared out of the main function
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
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.
#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.
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.