C while-loop not stopping - c

#include <cs50.h>
#include <stdio.h>
int main(void) {
printf("Enter your change: ");
int pennies = 0, nickels = 0, dimes = 0, quarters = 0;
float change = GetFloat();
while (change > 0) {
if (change >= 0.25) {
quarters++;
change -= 0.25;
}
else if (change >= 0.10) {
dimes++;
change -= 0.10;
}
else if (change >= 0.05) {
nickels++;
change -= 0.05;
}
else if (change >=0.01) {
pennies++;
change -= 0.01;
}
// force break
else {
printf("%1.2f - Num. of change left\n", change);
break;
}
}
printf("Quarters: %d\n", quarters);
printf("Dimes: %d\n", dimes);
printf("Nickels: %d\n", nickels);
printf("Pennies: %d\n", pennies);
return 0;
}
Hello, I'm currently new to C and I'm taking Harvard's CS50 class online. The "change" variable seems to go down to 0.00 without stopping the while-loop. This forced me to type in "break" at the end. What is wrong with my code?
This is from problem set 1 by the way.

There are problems with how floating point numbers are represented in a computer memory. If in short: not all numbers can be stored precisely. Please read this page for more details: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
You can use this service to check the representations of floats in a computer: http://www.binaryconvert.com/result_float.html
Regarding your case, let's assume you have entered 0.4. That means it should be divided into 0.25 + 0.1 + 0.05. And change is supposed to be zero, but:
0.40 == 0.4000000059604644775390625000,
minus
0.25 == 0.2500000000000000000000000000 (exact),
minus
0.10 == 0.1000000014901161193847656250,
minus
0.05 == 0.0500000007450580596923828125
is
0.00 == 0.0000000037252902984619140625
As you can see, the final result is slightly above zero, what prevents your loop from ending.
Generally, if you need to count money, you should use int instead to count "cents". Or custom types. Or long arithmetic. Or whatever, but not floating points, because money in most countries needs only two positions after a point, thus this point needs not to be floating.

You should not use floating point numbers for representing numbers that are integral by nature. Floating point arithmetic is a problem here. Change in most cases will never be equal to 0. You should just do everything with integers and it will work. Algorithm looks fine.
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
http://floating-point-gui.de/

As others have said, this is a floating point issue. Here's your problem:
else if (change >=0.01) {
pennies++;
change -= 0.01;
}
What's probably happening is that change ends up very slightly higher than 0.01, so when you subtract 0.01 from it, it ends up being slightly greater than zero, but less than 0.01, and you have no if clauses to deal with that eventuality, so it goes on forever. Your printf() shows zero because you're rounding it down to two decimal places, so it looks like 0.00 even though it's probably 0.00001 or something.

it isn't wise to use floats for this, as stated a several times here...
but logically you can do what you are trying, and I suspect it has to do with comparison and promotion rules in C... but I would guess this will fix your problem:
while (change > 0.0f)
that way you are comparing like types...
really you should change to using int, long, or long long... and representing cents rather than dollars.

Untested, but here's how I'd have written it. It uses int rather than float to avoid rounding problems, has a table-driven computation for each of the coins, and does division rather than repeated subtraction.
int change = GetFloat() * 100 + 0.5;
struct {const char *name; int value;} coins[] = {
{"Quarters", 25},
{"Dimes", 10},
{"Nickels", 5},
{"Pennies", 1},
};
for (int i = 0; i < 4; i++) {
int coin = change / coins[i].value;
change %= coins[i].value;
printf("%s: %d\n", coins[i].name, coin);
}

You should use the integer equivalent of getFloat(), or use an integer variable to do the comparisions. The code is going wrong because of floating point issues.
#include<math.h> // for round
...
...
int change = int)100 * round(getFloat());

Related

How to round up in C

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
const double TAX = 0.13;
double small = 17.96;
double subTotal = small * 6;
double taxes = subTotal * TAX;
printf("j SubTotal: %9.4lf Tax: %9.4lf \n", (double)subTotal, (double)taxes);
return 0;
}
The required output is
SubTotal: 107.7600 Tax: 14.0100 should come out.
My output is:
SubTotal: 107.7600 Tax: 14.0088
What should I do?
The solution is to not ever use floating point types for currency.
If you have a decimal type available, use it.
If you don't, write one.
Or, at a minimum, use long integers to store cents.
If you want to round to two decimal places, multiply by one hundred add one half, truncate to an int and then divide by one hundred. Like,
double round(double v) {
return ((int)(v * 100 + .5)) / 100.;
}
Then you can call that like
double taxes = round(subTotal * TAX);
And I get (with no other changes)
j SubTotal: 107.7600 Tax: 14.0100
C provides useful rounding functions rint(), round(), nearby(), llround() that well handle rounding corner cases.
To round to the nearest 100th, scale the value by /100.0, round and scale back.
#include <math.h>
double value = ...;
value *= 100.0;
value = round(value); // or rint(), nearby()
value /= 100.0;
At this point, value may not exactly be of the form ddd.dd but will be the closest double to that form. Printing with "%.4f" will then print to the closest 0.0001.
printf("%9.4lf\n", value);
Alternatively, take money and round to the smallest monetary unit - suppose OP wants to the nearest cent (0.01).
long long value_cents = llround(value * 100.0);
printf("%lld.%02d00", amount / 100, abs(amount % 100));
It’s a weird requirement to display four decimal places while rounding to two, but you can satisfy it by displaying two decimal places and hard-coding the characters 00 after it:
printf("j SubTotal: %9.2f00 Tax: %9.2f00 \n", subTotal, taxes);
Do not use floating point numbers for currency because they are tricky and inexact in many cases. Here is a working solution that gives you the exact output you want, but you should know it is strange to print more than two digits after the decimal point if those extra digits are always zero.
The + 99 in the code below is the trick you need to make the calculation always round up, instead of rounding down which is the normal behavior of unsigned integer division.
#include <stdio.h>
#include <stdint.h>
void print_money_with_strange_format(uint64_t amount)
{
printf("%llu.%02llu00", amount / 100, amount % 100);
}
int main(void)
{
uint64_t tax_rate = 13;
uint64_t small = 1796;
uint64_t subtotal = small * 6;
uint64_t tax = (subtotal * tax_rate + 99) / 100;
printf("SubTotal: ");
print_money_with_strange_format(subtotal);
printf(" Tax: ");
print_money_with_strange_format(tax);
printf("\n");
}
If you want to round the output to two decimals, but still producing four on output, just use
printf("%9.2f00", value);
and the value will be rounded to two decimals, and two zeros will be appended to it. But, why the computer should round 88 to 100 in a calculation, when you have not commanded it to round numbers at some place?
To round a number when the first decimal is over .5, you can just add 0.5 and then truncate the result. In case you want to do it at some position, just multiply the number by the required power of ten (in this case 100) and after the truncation, divide it again by that power(100), as proposed by other answers.

Rounding function in C

So i am trying to write a code which can allow me to round UP any number to 3 decimal places. My code for rounding up a number was like this :
for (rowIndex = 0; rowIndex < MAX_ROWS; rowIndex++)
{
for (columnIndex = 0; columnIndex < MAX_COLUMNS; columnIndex++)
{
printf("%.3f ", ceil(rawData[rowIndex][columnIndex] * 1000.0) / 1000.0);
}
}
But yesterday my teacher told us to use a code which has a structure like this:
float roundValue(float value, int decimalPlaces)
{
// Place rounding code here
return value;
}
i am not quite sure how to write the code in this format! I am a beginner in coding so this might be so silly.
UPDATE:
so i just read all the comments below and tried to write the code but still has a problem. my code is :
double roundValue(double value, int decimalPlaces)
{
value = roundf( value * pow(10, decimalPlaces)) / pow(10, decimalPlaces);
return value;
}
int main(void)
{
int rowIndex = 0;
int columnIndex = 0;
double rawData[MAX_ROWS][MAX_COLUMNS]; // 2-dimensional array to store our
raw data
double value = rawData[MAX_ROWS][MAX_COLUMNS];
int decimalPlaces = 3;
// Print out the roundup data array
printf(" --- ROUNDED DATA ---\n");
for (rowIndex = 0; rowIndex < MAX_ROWS; rowIndex++)
{
for (columnIndex = 0; columnIndex < MAX_COLUMNS; columnIndex++)
{
printf("%.3f ", roundValue(value, 3));
}
printf("\n");
}
return 0;
}
it gives me only 0 for all the numbers.
Based on this answer, you could use the roundf function found in math.h:
#include <stdio.h>
#include <math.h>
/* function that rounds a float to the specified number of decimals */
float roundValue(float value, int decimalPlaces)
{
value = roundf(value * pow(10, decimalPlaces)) / pow(10, decimalPlaces);
return value;
}
/*to see the results: */
int main()
{
float value = 12.34567;
printf("%f", roundValue(value, 3));
return 0;
}
Compilation/run:
$ gcc -lm main.c
$ ./a.out
12.346000
He just told you to write your code in a function that you can call in the main() function.
So instead of rewriting your code every time you need a round value you can use a function, you give it the number that you want to calculate the round value for, and it will give you the result so your code won't be repetitive
Essentially it can't be done. The problem is that 0.1, or 0.001, cannot be represented in floating point format exactly. So you can only round to the nearest representation rounded = floor(x * 1000 + 0.5)/1000.0. It's best to use the full accuracy of the double, then round at the last moment, for display.
printf("%.3g", x);
will achieve this for you. In combination with strtod it's also another technique for rounding.
.. to round UP any number to 3 decimal places.
my teacher told us to use a code ... like float roundValue(float value, int decimalPlaces)
Without going to higher precision, it is very difficult to meet OP's goal with the best answer for all value.
Rounding a floating pointer value a) up or b) to the nearest representable 0.001 (or 10-n) is usually done in steps.
1) Multiply by 10n
2) Round a) up or b) to nearest
3) Divide by 10n
float roundValue(float value, int decimalPlaces) {
// form the power of 10
assert(decimalPlaces >= 0 && decimalPlaces <= 9);
int power_of_10 = 1;
while (decimalPlaces-- > 0) power_of_10 *= 10;
double fpower_of_10 = power_of_10; // or just use `pow(10, decimalPlaces);
Scaling by a power of 10 introduces imprecision. This slight error is magnified in the rounding step. A simple work-around it to use higher precision math. Fortunately the coding goal started with a float value and double often has higher precision.
Scaling by a power-of 10 can cause overflow, yet that is not likely when value is float and the product is double which has a wider range.
double y = value * fpower_of_10;
// round
double rounded_y = ceil(y); // round up
// or
double rounded_y = round(y); // round to nearest
The quotient will rarely provide an exact multiple of 0.001 (or whatever power-of-10) but a floating point value that is near a multiple of 0.001.
y = rounded_y / fpower_of_10;
return y;
}
Usage follows. Recall that unless your floating point types use a FLT_RADIX == 10 (very rare these days, usually 2), The result with only be near the desired "number to n decimal places.". If done well, the result will be the nearest possible float/double.
printf("%f\n", roundValue(123.456789, 3));
printf("%.10f\n", roundValue(123.456789, 3)); // to see more
More: an easy way to avoid overflow issues if higher precision is not available or used is to recognize that great C floating-points values have no fractional part and need no rounding.
float roundValue(float value, int decimalPlaces) {
float int_ptr;
float frac_part = modff(value, &int_ptr);
if (frac_part == 0) return value;
double pow10 = pow(10, decimalPlaces);
return round(value * pow10)/pow10; // or ceil()
}
There are other small subtle issues not noted here. double rounding, NaN, rounding mode, round() vs. rint(), nearbyint().

a slight confusion with floating point values in C. (cs50 pset1 greedy.c)

I can't understand why the code below doesn't work properly with the value 4.2. I learnt using a debugger that 4.2 isn't actually the number four point two; rather as a floating point value 4.2 becomes 4.19999981
To make up for this, I just added change = change + 0.00001; there on line 18.
Why do I have to do that? Why is this the way floating point integers work?
#include <stdio.h>
#include <cs50.h>
float change;
int coinTotal;
int main(void)
{
do {
// Prompting the user to give the change amount
printf("Enter change: ");
// Getting a float from the user
change = get_float();
}
while (change < 0);
change = change + 0.00001;
// Subtracting quarters from the change given
for (int i = 0; change >= 0.25; i++)
{
change = change - 0.25;
coinTotal++;
}
// Subtracting nickels from the remaining change
for(int i = 0; change >= 0.1; i++)
{
change = change - 0.1;
coinTotal++;
}
// Subtracting dimes from the remaining change
for(int i = 0; change >= 0.05; i++)
{
change = change - 0.05;
coinTotal++;
}
// Subtracting pennies from the remaining change
for(int i = 0; change >= 0.01; i++)
{
change = change - 0.01;
coinTotal++;
}
// Printing total coins used
printf("%i\n", coinTotal);
}
Typically float can represent about 232 different values exactly. With float, 4.2 is not one of them. Instead the value is about 4.19999981 as OP has reported.
Working with fractional money is tricky. Rarely is float an acceptable type for money. This details some alternatives like base-10 FP, double, integers and custom types.
If code stays with some FP type, change >= 0.1, and other compares, need to alter to change >= (0.01 - 0.005) or the like. The compare needs to be tolerant of values just less than or greater than a multiple of 0.01.
As you have discovered. It's impossible to represent rational numbers as floating-point values on computers, due to the fact that the machine is storing it in a somewhat fixed sized ammount of bits.
The most common standard is IEEE 754 Check here
Most commonly you will work with floats that are in single precision (32 bits in total). The number is represented as 1 bit for sign, 8 bits for exponent , 23 bits for mantissa.
The representation is as follows x=S*M*B^E where:
S - sign (-1 or 1)
M - mantissa (a normalized fraction)
B - Base (here as 2)
E - exponent ( 8bits -> -128,127 or 0,255 depending on definition in standard)
This fraction is (M) causing the problems with accurate representation of values. You need to represent a certain aproximation while being given a limited ammount of bits (You can only accurately represent values that can be combined by summing 1/2, 1/4, 1/8... )
Commonly 32 bits allows you for precision for around 6 places in fraction.
You can use 64 bit (double) for a greater range and slightly better precision.
Make every number in your program 100 times bigger, use the math.h roundf function, and divide the result by 100 when you are about to print the value to the screen.

In this code, Why am I getting wrong output only for input value of 4.2 while it is working well for other values?

The following code converts dollars (floating values) into cents (integer values). Here 1 dollar == 100 cents. The code works flawlessly except for one value i.e 4.2. It gives output as 419 instead of 420 for 4.2 as input. Where is the bug?
#include <stdio.h>
int main(void)
{
float change;
do
{
printf("O hai! Enter amount in dollars to convert in cents.\n");
scanf("%f",&change); //accepts input in dollars
} while(change < 0.00);
int i = change * 100; //converts dollars into cents
printf("The equivalent cents are %d\n",i);
}
You have this behavior because of the way a float is represented.
In IEEE 754, 4.2 is actually stored as 4.19999980926513671875 so that when you multiply it by 100 and cast it back to an int, you get 419 (i.e. the integer part of the result).
A solution would be to use
int i = (int) roundf(change * 100);
or
int i = (int) lrintf(change * 100);
with #include <math.h>.
Many floating point values do not have an exact representation in base 2.
You can try adding a very small value to push the value a little bit:
int i = (change + 0.0001) * 100; //converts dollars into cents
As you can see here when you store a value in a float the actual number stored is not always what you expected. This is due to how floats are represented in binary (you can learn more on wiki).
Now, as shown in the 1st link, when you try to store 4.2 in change, you actually store 4.19.... Multiply it by 100, store it inside an int,and you get 419.
Changing your float into double will give you better (double) precision, and in your case, it will yield the expected result
double change; # float changed to double
do
{
printf("O hai! Enter amount in dollars to convert in cents.\n");
scanf("%lf",&change); //accepts input in dollars # "%f" changed to "%lf"
} while(change < 0.00);
int i = change * 100; //converts dollars into cents
printf("The equivalent cents are %d\n",i);
input: 4.2
output: 420
on my machine.
Note that using double is not a fail-safe. It can also give misleading results, but it should behave better than float.
In this case that you know that the decimals for work with money are 2, I suggest that work with float representation with 3 decimals, and then the result must do round up to 2 decimals. Is important be carefully, because the working with money is very delicate.
Hope this help.

Calculating smallest number of coins error

I've recently started an online course in C, and am working through the second question in PS1. The question requires us to request an input of change from a user in dollars, and to calculate the smallest number of coins you can give them that change with, provided you are only allowed 25 cent, 10 cent, 5 cent and 1 cent coins.
For example 50 cents would be 2 25 cent coins, and 65 cents would be 2 25 cent coins, 1 10 cent coin and 1 5 cent coin.
Here is my code:
#include <stdio.h>
#include <cs50.h>
int main(void)
{
float change = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
int remainder3 = 0;
.
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
//converts amount in dollars to cents
change = change*100;
//We want to use the largest number of big cois as possible to make up the change.
// This calculates the remainder (if any) after dividing the change by 25. % = modulo, only works with integer operands.
remainder = (int)change % 25;
//(change - remainder) gets us the largest number divisible by 25. This line then calculates
// the maximum number of 25cent coins we can use, and sets this number equal to the coinCounter.
coinCounter = ((int)change - remainder)/25;
//Finds the remainder (if any) when dividing the last remainder by 10.
remainder1 = remainder % 10;
//(remainder - remainder1) gets us the largest number divisible by 10. Dividing this by 10, we
// determine the max amount of 10 cent coins we can use to make up the required change. We then add
// this number of coins to the total coinCounter.
coinCounter = coinCounter + ((remainder - remainder1)/10);
//Again, take the remainder (if any) from the last calculation, and find the remainder when dividing by 5.
remainder2 = remainder1 % 5;
// (remainder1 - remainder2)/5 tells us the number of 5 cent coins we need to make up the required change.
// We add the number of coins to the coin counter.
coinCounter = coinCounter + ((remainder1 - remainder2)/5);
//Finds the remainder when dividing last remainder by 1. There will actually be no remainder, so remainder 3 will
// equal zero.
remainder3 = remainder2 % 1;
//Here, (remainder2 - remainder1)/1 Finds the number of 1 cent coins required to make up the left change.
// remainder3 will always be zero. Hence (remainder2)/1 will always be equal to remainder 2. We add this number
// of 1 cent coins to the coinCounter.
coinCounter = coinCounter + ((remainder2 - remainder3)/1);
//We print out coinCounter, which is the smallest number of coins required to make up the change.
printf("%i\n",coinCounter);
}
Now I am new to programming, so I am very aware that there are probably far more efficient ways of tackling this problem. However, this seems to work fairly well. However, strangely, I get an incorrect result when I try '4.2'. I should get 18 coins (16 25 cent coins and 2 10 cent coins), however the program displays 22. It works well for all other numbers I have tried however.
I cannot figure out what I have done wrong. I feel like it either has something to do with where I change dollars to cents by multiplying by 100, OR, where I calculate the modulo and cast change to an int, but I unfortunately cannot figure it out alone.
I have heavily annotated my code so it is somewhat easier to understand. I hope someone can help me with this!
I would do something simpler, like:
int main(void)
{
float change = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
change = change*100;
coinCounter = (int)change/25; //number of 25cents
remainder = change % 25; //rest
if(remainder > 0){
coinCounter += (int)remainder/10; //number of 10cts
remainder1 = remainder%10;
}
if(remainder1 > 0){
coinCounter += (int)remainder1/5; //number of 5cts
remainder2 = remainder1%5
}
coinCounter += remainder2; //number of 1cts
printf("%i\n",coinCounter);
}
Does it solve your problem with 4.2 ? I can't test right now.
The issue is that you have taken the change variable as a float, while all the other variables are ints.
The conversion of a float to an int introduces small unpredictable errors and can fail in some cases.
If you are interested in there is a very good article here.
I would suggest that you take the input as cents, or if that is not possible, take another integer variable and convert to cents at the start of the program and use that instead in the calculations.
As EOF has (rather snarkily) pointed out in their comment you are running into an issue with floating point numbers. Floating point numbers are a not perfect, there are many (infinitely many) numbers that can't be exacltly represented by a C float or double.
There's lots of good information on the web about this, for example here but the short explanation is that some decimal values when calculated in C using floats give the wrong answer and one such number is 4.2 * 100 in your particular compiler.
One possible solution in your case is to convert the float to a long, so something like:
change = change * 100 ;
long value = change >= 0 ? (long)(change+0.5) : (long)(change-0.5) ;
This should give you the exact number of cents and remove the small error in the floating calculation.
As an aside these effects can be dificult to see sometimes, try printing the result of this:
float x = 4.2 * 100 ;
float y = 4.2 ;
y = y * 100 ;
In my compiler this does result in 420 in x but 419.99... in y.
As others have pointed out, floating point values cannot always be represented perfectly. To address the error, you can round to the nearest integer. Here is a very simple function to start with:
int round(float number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}
Use it in your code like this:
int main(void)
{
float change = 0;
int changed = 0;
int coinCounter = 0;
int remainder = 0;
int remainder1 = 0;
int remainder2 = 0;
int remainder3 = 0;
do
{
printf("Please enter the change in dollars: ");
change = GetFloat();
}
while(change <= 0);
//converts amount in dollars to cents
changed = round(change*100);//changes 419... to 420 etc.
...(more code)
You will have to experiment with corner cases to make it work well for all conditions, but this will get you started.
Note: this code example for rounding is over simplified, and provided just to get you started. The problem is really more complicated as illustrated by this conversation dealing with rounding floats to nearest integer value.

Resources