This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
Hi so I'm struggling to figure out what's wrong with my code. I'm really new at this so bear with me. Comments might be a little messy atm.
#include <stdio.h>
int main(void)
{
double cost, gstCost, newCost; // initial cost, cost of gst by itself, new cost after gst
int loonies, quarters, dimes, nickels, pennies; // used for quantity of coins
float loonreq, quartreq, dimereq, nickreq, penreq; // cost required after deduction of the corresponding coin
printf("Please enter the amount to be paid: $");
scanf("%lf", &cost); // scanf allows to input an amount as a double ("%lf")
gstCost = cost * .13 + .005; // .13 for gst and add 0.005 to round up or down
printf("GST: %.2lf\n", gstCost);
newCost = cost + gstCost;
printf("Balance owing: $%.2lf\n", newCost); // original cost + gst cost
loonies = newCost; // loonies will output as integer when cost has decimals
printf("Loonies required: %d", loonies);
if (loonies == 0) // == used to compare equality
loonies = 1; // if loonies = 0, loonreq will be infinite causing code to crash and stop
loonreq = (float)((int)(100 * newCost) % (100 * loonies)) / 100; // casting int and * 100 on float values for modulo since it can only calculate for integer value
printf(", balance owing $%.2f\n", loonreq); // %.2f shows a float with 2 decimal places
quarters = 100 * loonreq / 25; // 100*loonreq allows the code to find how many quarters by dividing by 25
printf("Quarters required: %d", quarters);
if (quarters == 0)
quarters = 1;
quartreq = (float)((int)(100 * loonreq) % (int)(100 * (quarters * .25))) / 100;
printf(", balance owing $%.2f\n", quartreq);
dimes = 100 * quartreq / 10;
printf("Dimes required: %d", dimes);
if (dimes == 0)
dimes = 1;
dimereq = (float)((int)(100 * quartreq) % (int)(100 * (dimes * .10))) / 100;
printf(", balance owing $%.2f\n", dimereq);
nickels = 100 * dimereq / 5;
printf("Nickels required: %d", nickels);
if (nickels == 0)
nickels = 1;
nickreq = (float)((int)(100 * dimereq) % (int)(100 * (nickels * .05))) / 100;
printf(", balance owing $%.2f\n", nickreq);
pennies = 100 * nickreq / 1;
printf("Pennies required: %d", pennies);
if (pennies == 0)
pennies = 1;
penreq = (float)((int)(100 * nickreq) % (int)(100 * (pennies * .01))) / 100;
printf(", balance owing $%.2f\n", penreq);
return 0;
}
When I run this code on Visual Studio, I get the correct outputs for certain inputs like 8.68 but when I submit this file through PuTTY for my professor, it tests it for me and I get an incorrect balance (a penny off) after dimes deducted. When I put in a value like 76.54, I'm a penny off after the deduction of loonies. Inputting a value like 76.76, I get the correct output. I don't exactly know what's happening. My professor looked at my code and said it's because of type changes? and recommended that I use this method instead, example
dimes = (balance / 100) / 0.1;
balance = (int)(balance) % 10;
I'm not sure how to use this method though.
Edit: I need to use the modulus operator and casting for this assignment. gcc is used when I submit on PuTTy.
The rounding logic is not giving the correct answer. Say we have an input 123. The GST should be 15.99. However your code will give 16.00. To fix this try replacing gstCost = cost * .13 + .005; with gstCost = (round(cost * .13 * 100) / 100);
Don't use float/double at all for money. Computers are binary and use base 2 math. Not all decimal values (base 10) can be represented precisely in base 2 floating point, causing rounding errors. Do your math with int (or long long) representing pennies and it will be accurate up to the max value of a 32-bit signed int (millions) or 64-bit signed long long (quadrillions).
(float)((int)(100 * quartreq) % (int)(100 * (dimes * .10))) / 100;
I'm sure that changing types like float to int and vise versa can lose a some data throught the parsing part.
example: you have a double variable set as 1.2 when you parse it to int it become 1 and not 1.2 and it won't become 1.2 when you parse it back to double.
Do your calculations with the float type and if you want to change data type only parse it in the final result.
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Why not use Double or Float to represent currency?
(16 answers)
How to represent currency or money in C
(5 answers)
How to read and store currency values in C [duplicate]
Closed 2 years ago.
As a part of the CS50 course we're tasked to create a program (in C) that calculates the least amount of coins ($0.25, $0.10, $0.05 and $0.01) from a value submitted by the user.
My idea was to take the input value and multiply by 100 and use integers since the only value of interest is the number of coins and not the monetary value, hence I don't have to tinker with any decimals.
The code is:
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
//If it's NOT a positive number, do this.
float n;
do
{
n = get_float("Change owed: \n");
}
while (n <= 0);
//Multiplying change owed with 100 to avoid having to deal with decimals.
int cash = n * 100;
//Calculating the number of quarters ($0.25).
int quarters = cash / 25; //How many full quarters per cash.
int quarters_rem = cash % 25; //The remainder after full amout of quarters in cash.
printf("Number of quarters: %i\n", quarters); //Test how many quarters.
printf("Remainder: %i\n", quarters_rem); //Test how much remainder.
//Calculating the number of dimes ($0.10).
int dimes = quarters_rem / 10; //How many full dimes from the remainder when all quarters are deducted.
int dimes_rem = round(quarters_rem % 10); //The remainder after full amount of dimes in quarters_rem.
printf("Number of dimes: %i\n", dimes); //Test how many dimes.
printf("Remainder: %i\n", dimes_rem); //Test how much remainder.
//Calculating the number of nickels ($0.05).
int nickels = dimes_rem / 5; //How many full nickels from the remainder when all dimes are deducted.
int nickels_rem = round(dimes_rem % 5); //The remainder after full amount of nickels in dimes_rem.
printf("Number of nickels: %i\n", nickels); //Test how many nickels.
printf("Remainder: %i\n", nickels_rem); //Test how much remainder.
//Calculating the number of cents ($0.01).
int cents = nickels_rem; //How many full cents from the remainder when all nickels are deducted.
printf("Number of cents: %i\n", cents); //Test how many nickels.
//Prints the least number of coins to be returned.
int coins = quarters + dimes + nickels + cents;
printf("%i\n", coins);
}
The thing is that when I run the code and enter 2.2, 6.2 or 8.2, the output gives me a remainder of 20 after calculating the quarters. 2.2 x 100 = 220 -> 25 x 8 = 200 which gives a remainder of 20, as expected. This is true for 2.2, 6.2, 8.2, 10.2, 12.2, 14.2 and so on.
However, this is not! true if I enter 4.2! If I enter 4.2 I expect: 4.2 x 100 = 420 -> 25 x 16 = 400 which ought to give me a remainder of 20, but instead I get a remainder of 19? I don't understand why the remainder is 19 in this instance but 20 in the others?
Typical implementation of floating-point stores numbers in binary format, so it cannot precisely store some of decimal numbers.
With this program
#include <stdio.h>
int main(void) {
float x = 4.2;
float y = x * 100;
printf("%.10f\n", y);
return 0;
}
I got output:
419.9999694824
This shows that 4.2f * 100 became slightly smaller than 420 and converting that to int will result in 419 instead of 420.
To avoid this, you should add smaller value before converting float to int in this case.
int cash = n * 100 + 0.1;
** UPDATE: This was solved, by Loc Tran! Thank you LocTran!! **
I am writing a program, (using strictly C) which calculates the minimum change in US denominations. After my program reaches dimes (the first denomination that is not divisible by a whole number the program seems to not want to continue to nickels and pennies.
I have tried to use an if statement, excluding dimesDue value if returning a zero, but cant seem to figure it out. If you notice, I also had to make a new change variable for each denomination, based on the previous denominations deduction from the total change amount. I would prefer to simplify this and specify the new value after each calculation, but could not.
// Amount Tendered and Purchase amount converted to pennies
amountDue = 2117;
amountGiven = 10000;
// Creating a new change amount for each denomination, based on each previous computation
change = amountGiven - amountDue;
change10s = change % (20 * 100);
change5s = change % (10 * 100);
change1s = change % (5 * 100);
changeQs = change % (1 * 100);
changeDs = change % 25;
changeNs = change % 10;
changePs = change % 1;
// Using each new change amount to calculate amount of denomination
twentiesDue = (change / 20) / 100;
tensDue = (change10s / 10) / 100;
fivesDue = (change5s / 5) / 100;
onesDue = (change1s / 1) / 100;
quartersDue = (changeQs / 25);
dimesDue = (changeDs / 10);
nickelsDue = (changeNs / 5);
penniesDue = (changePs / 1);
printf("Amount Due: $21.17\nAmount Tendered: $100\n\n");
printf("Change Due:\n(by denomination)\n");
printf("Twenties: %d\n", twentiesDue);
printf("Tens: %d\n", tensDue);
printf("Fives: %d\n", fivesDue);
printf("Ones: %d\n", onesDue);
printf("Quarters: %d\n", quartersDue);
printf("Dimes: %d\n", dimesDue);
printf("Nickels: %d\n", nickelsDue);
printf("Pennies: %d\n", penniesDue);
The program reaches dimes (the first denomination that does not equal a whole number) and does not continue on to caculate the amount of nickels and pennies. Because the remainder of change left after quarters is 8 cents, this is not divisible by 10. but I cant figure out how to specify to ignore this using a if statement!
So the result is once the program reaches dimes, all variable thereafter compute to zero. But there should be one nickel and three pennies!
Here is the result when I run it:
Amount Due: $21.17
Amount Tendered: $100
Change Due:
(by denomination)
Twenties: 3
Tens: 1
Fives: 1
Ones: 3
Quarters: 3
Dimes: 0
Nickels: 0
Pennies: 0
Although this solution works, I can't use it.
Modulus operator MUST be used.
You have a problem with calculating the remaining amount after changing with a monetary value. It is similar procedure to get all digits in a number. For example, with 198 after get 1, the remaining is 198-1*100 = 98, then we get 9 , the remaining is 98-9*10=8, and get 8 then we done.
You calculated with a wrong formula. Here is my calculation with the same manner of getting digits in a number, and the entire solution:
#include <stdlib.h>
#include <stdio.h>
int main()
{
// Amount Tendered and Purchase amount converted to pennies
int amountDue = 2117;
int amountGiven = 10000;
// Using each new change amount to calculate amount of denomination
// getting 20dollars notes
int change = amountGiven - amountDue;
int twentiesDue = (change / 20) / 100;
// get the remaining after change 20dollar notes, and
// then divide 10*100 for getting 10dollars notes
int change10s = change % (20*100);
int tensDue = (change10s / 10) / 100;
// get the remaining after change 10dollar notes, and
// then divide 5*100 for getting 5dollars notes
int change5s = change10s % (10*100);
int fivesDue = (change5s / 5) / 100;
// get the remaining after change 5dollar notes, and
// then divide 1*100 for getting 1dollars notes
int change1s = change5s % (5*100);
int onesDue = (change1s / 1) / 100;
// get the remaining after change 1dollar notes, and
// then divide 25 for getting quarter coins
int changeQs = change1s % (1*100);
int quartersDue = (changeQs / 25);
// get the remaining after change quarter coins, and
// then divide 10 for getting dime coins
int changeDs = changeQs % 25;
int dimesDue = (changeDs / 10);
// get the remaining after change dime coins, and
// then divide 5 for getting nickel coins
int changeNs = changeDs % 10;
int nickelsDue = (changeNs / 5);
// get the remaining after change nickel coins, and
// then divide 1 for getting 1cent coins
int changePs = changeNs % 5;
int penniesDue = (changePs / 1);
printf("Amount Due: $21.17\nAmount Tendered: $100\n\n");
printf("Change Due:\n(by denomination)\n");
printf("Twenties: %d\n", twentiesDue);
printf("Tens: %d\n", tensDue);
printf("Fives: %d\n", fivesDue);
printf("Ones: %d\n", onesDue);
printf("Quarters: %d\n", quartersDue);
printf("Dimes: %d\n", dimesDue);
printf("Nickels: %d\n", nickelsDue);
printf("Pennies: %d\n", penniesDue);
return 0;
}
#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.
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.
I am a C++ programmer trying to get a grasp of the C language syntax and I do not understand why I'm getting garbage values when I use pointers in this function.
#include<stdio.h>
#include <math.h>
void separate(double, double *dollar, double *quarter, double *dime, double *nickle, double *penny);
int
main(void)
{
double amount = 38.39, change, paid = 40.0, dollar, quarter, dime, nickle, penny;
change = paid - amount;
separate(change, &dollar, &quarter, &dime, &nickle, &penny);
printf("Your total change is: $%d\n", change);
printf("Dollars: %d\n", dollar);
printf("Quarters: %d\n", quarter);
printf("Dimes: %d\n", dime);
printf("Nickles: %d\n", nickle);
printf("Pennies: %d\n", penny);
getchar();
return (0);
}
void separate(double change, double *dollar, double *quarter, double *dime, double *nickle, double *penny)
{
double coins;
coins = change - floor(change);
*dollar = floor(change);
*quarter = coins / 25;
coins = coins - (*quarter * 25);
*dime = coins / 10;
coins = coins - (*dime * 10);
*nickle = coins / 5;
*penny = coins - (*nickle * 5);
}
you are printing using %d for doubles! try %f
printf("Your total change is: $%f\n", change);
printf("Dollars: %f\n", dollar);
printf("Quarters: %f\n", quarter);
printf("Dimes: %f\n", dime);
printf("Nickles: %f\n", nickle);
printf("Pennies: %f\n", penny);
I suspect that your problem is that you're not doing division correctly.
Take a look:
void separate(double change, double *dollar, double *quarter, double *dime, double *nickle, double *penny)
{
// for your example, change is initially 1.61
double coins;
coins = change - floor(change); // .61
*dollar = floor(change); // 1
*quarter = coins / 25; // .0244
coins = coins - (*quarter * 25); // 0
*dime = coins / 10; // 0
coins = coins - (*dime * 10); // 0
*nickle = coins / 5; // 0
*penny = coins - (*nickle * 5); // 0
}
Integer division and floating point division don't work the same way. You should instead multiply by 100 to get the number of cents, divide by 25 to get the number of quarters, then floor to make it a whole number.
*quarters = floor(coins * (100 / 25)); // floor(2.44) = 2
coins = coins - *quarters * 25; // .11
Repeat as needed to get quantities of other coins.
Also, everyone else has mentioned that you're using %d to print doubles instead of %f (%d is an integer format string) so I'll mention it too, because it's part of the problem.
Indeed. Rather unintuitive, but %d in a printf statement is for integers.Try printing with %f for floating point numbers.
I also recommend you take a look at this:
You're trying to print double variables with %d, printf then will take the memory of double (or part of it) as memory of integer variable, since printf use va_list as a pointer to arguments, if you assign a inappropriate format, the type of arg point will go wrong too.
Replace all %d with %f.