discrepancies in rounding off in C - c

I'm having an issue where when I print a double value it is inconsistently either rounding up or down. I am using the format:
printf("%.2lf", double);
what could be the possible issue here? thanks!

Any decimal numeral in source code or input is converted to the binary format your C implementation uses for double. This changes the value away from the xxx.xx5 value. When it is then printed using %.2lf, it is the changed value that is rounded, not the original. There is no way to avoid this using only the value in a double.
With additional information, such as known limits on how many decimal digits the original numerals had or what values they may take, it might be possible to reconstruct the original value and round that. However, such information is not present in the question.

"fraction is exact at the 3rd decimal point"
As double uses a binary internal representation, most decimal fractions like 0.1, 0.01, 0.001 are not possible to represent exactly. Instead of the exact code value of x.xx5, a double near that is used, perhaps a tad lower or higher.
To recover that exact at the 3rd decimal point, scale the double by 1000.0 and round to nearest whole number.
double d1000 = round(d * 1000.0);
To print to 2 decimal places, round the d1000 to the nearest 10s, round and then divide by 100.0
double d100 = round(d1000 / 10.0) / 100.0;
printf("%.2lf", double);
In effect, code recovers by employing a double rounding.
Example:
#include <stdio.h>
#include <math.h>
void prt(double d) {
double d1000 = round(d * 1000.0);
double d100 = round(d1000 / 10.0) / 100.0;
printf("%.16e %.2lf\n", d, d100);
}
void prt3(double d) {
prt(nextafter(d, 0));
prt(d);
prt(nextafter(d, d*2));
}
int main() {
prt3(1203.505000);
prt3(1203.705000);
}
Output
1.2035049999999999e+03 1203.51
1.2035050000000001e+03 1203.51
1.2035050000000003e+03 1203.51
1.2037049999999997e+03 1203.71
1.2037049999999999e+03 1203.71
1.2037050000000002e+03 1203.71

In a comment you wrote
the fraction is exact at the 3rd decimal point
Your original number might have been, but once it's converted to double, which uses binary fractions internally, there's no such thing as a "third decimal point", and in fact decimal numbers like 0.001 and 0.005 simply cannot be represented exactly.
Here are some sample numbers, how they're represented as a double, and how they print as "%.2lf, that is, converted back to decimal and rounded to two places.
(Note that when I say "how they're represented as a double", what I'm really showing you is the internal binary representation converted back to decimal again. It's also interesting to look at the actual internal representation, in binary or hexadecimal, but it's harder to display meaningfully and doesn't really bear on today's question, so I'm not going to bother.)
input value
internal double value
printed "%.2lf"
1203.480
1203.4800000000000181899
1203.48
1203.485
1203.4849999999998999556
1203.48
1203.490
1203.4900000000000090949
1203.49
1203.495
1203.4949999999998908606
1203.49
1203.500
1203.5000000000000000000
1203.50
1203.505
1203.5050000000001091394
1203.51
1203.510
1203.5099999999999909051
1203.51
1203.515
1203.5150000000001000444
1203.52
1203.520
1203.5199999999999818101
1203.52
1203.525
1203.5250000000000909495
1203.53
1203.530
1203.5299999999999727152
1203.53
You can see that sometimes .xx5 is represented as .xx50000000001 and so rounds up as you expect, but sometimes it's represented as .xx49999999999 and so rounds down.
You asked "what could be the possible issue here", and that's what I've explained. Other answers contain suggestions on how you could adjust your code to work around the issue.

Related

Why does C print float values after the decimal point different from the input value? [duplicate]

This question already has answers here:
Why IEEE754 single-precision float has only 7 digit precision?
(2 answers)
Closed 1 year ago.
Why does C print float values after the decimal point different from the input value?
Following is the code.
CODE:
#include <stdio.h>
#include<math.h>
void main()
{
float num=2118850.132000;
printf("num:%f",num);
}
OUTPUT:
num:2118850.250000
This should have printed 2118850.132000, But instead it is changing the digits after the decimal to .250000. Why is it happening so?
Also, what can one do to avoid this?
Please guide me.
Your computer uses binary floating point internally. Type float has 24 bits of precision, which translates to approximately 7 decimal digits of precision.
Your number, 2118850.132, has 10 decimal digits of precision. So right away we can see that it probably won't be possible to represent this number exactly as a float.
Furthermore, due to the properties of binary numbers, no decimal fraction that ends in 1, 2, 3, 4, 6, 7, 8, or 9 (that is, numbers like 0.1 or 0.2 or 0.132) can be exactly represented in binary. So those numbers are always going to experience some conversion or roundoff error.
When you enter the number 2118850.132 as a float, it is converted internally into the binary fraction 1000000101010011000010.01. That's equivalent to the decimal fraction 2118850.25. So that's why the .132 seems to get converted to 0.25.
As I mentioned, float has only 24 bits of precision. You'll notice that 1000000101010011000010.01 is exactly 24 bits long. So we can't, for example, get closer to your original number by using something like 1000000101010011000010.001, which would be equivalent to 2118850.125, which would be closer to your 2118850.132. No, the next lower 24-bit fraction is 1000000101010011000010.00 which is equivalent to 2118850.00, and the next higher one is 1000000101010011000010.10 which is equivalent to 2118850.50, and both of those are farther away from your 2118850.132. So 2118850.25 is as close as you can get with a float.
If you used type double you could get closer. Type double has 53 bits of precision, which translates to approximately 16 decimal digits. But you still have the problem that .132 ends in 2 and so can never be exactly represented in binary. As type double, your number would be represented internally as the binary number 1000000101010011000010.0010000111001010110000001000010 (note 53 bits), which is equivalent to 2118850.132000000216066837310791015625, which is much closer to your 2118850.132, but is still not exact. (Also notice that 2118850.132000000216066837310791015625 begins to diverge from your 2118850.1320000000 after 16 digits.)
So how do you avoid this? At one level, you can't. It's a fundamental limitation of finite-precision floating-point numbers that they cannot represent all real numbers with perfect accuracy. Also, the fact that computers typically use binary floating-point internally means that they can almost never represent "exact-looking" decimal fractions like .132 exactly.
There are two things you can do:
If you need more than about 7 digits worth of precision, definitely use type double, don't try to use type float.
If you believe your data is accurate to three places past the decimal, print it out using %.3f. If you take 2118850.132 as a double, and printf it using %.3f, you'll get 2118850.132, like you want. (But if you printed it with %.12f, you'd get the misleading 2118850.132000000216.)
This will work if you use double instead of float:
#include <stdio.h>
#include<math.h>
void main()
{
double num=2118850.132000;
printf("num:%f",num);
}

How to round a float by casting as an int in C

So I am a second semester freshman in college. My teacher wants us to write a function that round a floating point number to the nearest hundredth. He said that we need to convert the floating point into an integer data type and then covert it back to a floating point. That's all he said. I have spent at least 5 hours trying different ways to do this.
This is my code so far:
#include <stdio.h>
int rounding(int roundedNum);
int main()
{
float userNum,
rounded;
printf("\nThis program will round a number to the nearest hundredths\n");
printf("\nPlease enter the number you want rounded\n>");
scanf("%f", &userNum);
rounded = rounding (userNum);
printf("%f rounded is %f\n", userNum, rounded);
return 0;
}
int rounding(int roundedNum)
{
return roundedNum;
}
Your instructor may be thinking:
float RoundHundredth(float x)
{
// Scale the hundredths place to the integer place.
float y = x * 100;
// Add .5 to cause rounding when converting to an integer.
y += .5f;
// Convert to an integer, which truncates.
int n = y;
// Convert back to float, undo scaling, and return.
return n / 100.f;
}
This is a flawed solution because:
Most C implementations use binary floating point. In binary floating-point, it is impossible to store any fractions that are not multiples of a negative power of two (½, ¼, ⅛, 1/16, 1/32, 1/64,…). So 1/100 cannot be exactly represented. Therefore, no matter what calculations you do, it is impossible to return exactly .01 or .79. The best you can do is get close.
When you perform arithmetic on floating-point numbers, the results are rounded to the nearest representable value. This means that, in x * 100, the result is, in generally, not exactly 100 times x. There is a small error due to rounding. This error cause push the value across the point where rounding changes from one direction to another, so it can make the answer wrong. There are techniques for avoiding this sort of error, but they are too complicated for introductory classes.
There is no need to convert to an integer to get truncation; C has a truncation function for floating-point built-in: trunc for double and truncf for float.
Additionally, the use of truncation in converting to integer compelled us to add ½ to get rounding instead. But, once we are no longer using a conversion to an integer type to get an integer value, we can use the built-in function for rounding floating-point values to integer values: round for double and roundf for float.
If your C implementation has good formatted input/output routines, then an easy way to find the value of a floating-point number rounded to the nearest hundred is to format it (as with snprintf) using the conversion specifier %.2f. A proper C implementation will convert the number to decimal, with two digits after the decimal point, using correct rounding that avoids the arithmetic rounding errors mentioned above. However, then you will have the number in string form.
Here are some hints:
Multiply float with "some power of 10" to ensure the needed precision numbers are shifted left
Cast the new value to a new int variable so the unwanted float bits are discarded
Divide the int by the same power of 10 but add use a float form of that (e.g 10.0) so integer gets converted to float and the new value is the correct value
To test, use printf with the precision (.2f)
The two most common methods of rounding are "Away From Zero" and "Banker's Rounding (To Even)".
Pseudo-code for Rounding Away From Zero
EDIT Even though this is pseudo-code, I should have included the accounting for precision, since we are dealing with floating-point values here.
// this code is fixed for 2 decimal places (n = 2) and
// an expected precision limit of 0.001 (m = 3)
// for any values of n and m, the first multiplicand is 10^(n+1)
// the first divisor is 10^(m + 1), and
// the final divisor is 10^(n)
double roundAwayFromZero(double value) {
boolean check to see if value is a negative number
add precision bumper of (1.0 / 10000) to "value" // 10000.0 is 10^4
multiply "value" by 1000.0 and cast to (int) // 1000.0 is 10^3
if boolean check is true, negate the integer to positive
add 5 to integer result, and divide by 10
if boolean check is true, negate the integer again
divide the integer by 100.0 and return as double // 100.0 is 10^2
ex: -123.456
true
-123.456 + (1.0 / 10000.0) => -123.4561
-123.4561 * 1000.0 => -123456.1 => -123456 as integer
true, so => -(-123456) => 123456
(123456 + 5) / 10 => 123461 / 10 => 12346
true, so => -(12346) => -12346
-12346 / 100.0 => -123.46 ===> return value
}
In your initial question, you expressed a desire for direction only, not the explicit answer in code. This is as vague as I can manage to make it while still making any sense. I'll leave the "Banker's Rounding" version for you to implement as an exercise.
Ok so I figured it out! thank yall for your answers.
//function
float rounding(float roundedNumber)
{
roundedNumber = roundedNumber * 100.0f + 0.5f;
roundedNumber = (int) roundedNumber * 0.01f;
return roundedNumber;
}
So pretty much if I entered 56.12567 as roundedNumber, it would multiply by 100 yielding 5612.567. From there it would add .5 which would determine if it rounds up. In this case, it does. The number would change to 5613.067.
Then you truncate it by converting it into a int and multiply by .01 to get the decimal back over. From there it returns the value to main and prints out the rounded number. Pretty odd way of rounding but I guess thats how you do it in C without using the rounding function.
Well, let's think about it. One thing that's helpful to know is that we can turn a float into an integer by casting:
float x = 5.4;
int y = (int) x;
//y is now equal to 5
When we cast, the float is truncated, meaning that whatever comes after the decimal point is dropped, regardless of its value (i.e. It always rounds towards 0).
So if you think about that and the fact that you care about the hundredths place, you could maybe imagine an approach that consists of manipulating your floating point number in someway such that when you cast it to an int you only truncate information you don't care about (i.e. digits past the hundredths place). Multiplying might be useful here.

Comparison of one float variable to its contained value

#include<stdio.h>
int main()
{
float a,b;
a=4.375;
b=4.385;
if(a==4.375)
printf("YES\n");
else
printf("NO\n");
if(b==4.385)
printf("YES\n");
else
printf("NO\n");
return 0;
}
Answer of this code :
YES
NO
I always thought if i compare a float with double value. it will never match to it. unless value is pure integer. but here float "a" has 4.375 is exact in it but "b" doesn't
printf("%0.20f\n",a);
printf("%0.20f\n",b);
This prints :
4.37500000000000000000
4.38500022888183593750
but if i print
printf("%0.20f\n",4.475);
It prints 4.47499990463256835938
How is this rounding effect is showing in some and not in others.
Can anyone explain this. how should "WE" judge when value in float variable will match to that contained in it and when it doesn't ?
The conversion from decimal fraction to a binary fraction is precise only if the decimal fraction can be summed up by binary fractions like 0.5, 0.25, ..., etc.
For example in your case
0.375 = 0.25 + 0.125 = 2-2 + 2-3
So it can be represented exactly by using binary fractions.
Where as the number 0.385 can not be represented by using binary fractions precisely. So numbers like 0.5, 0.25, 0.125, ..., etc. or a combination of these numbers can be represented exactly as floating point numbers. Others like 0.385 will give incorrect results when the comparison or equality operations are performed on them.
Floating points aren't magic.
They contain an exact value and if you compare it with that they will compare equal. The two problems are
1) Some operations are not always entirely exact due to precision issues. If you add one to a float and then subtract one then adding that one might have causes some loss of precision in the least significant value bits and when you subtract it you don't get back to quite the same value you expect.
2) It is not possible to exactly represent every decimal value in the floating point binary format. For example it is not possible to store the exact value of 0.1 in a floating point binary number in exactly the same way that you can't write the value of 1/3.0 as a decimal value exactly no matter how many digits you use.
But in your case if you store a value and compare it with that same value they SHOULD compare equal as they'll both have the same issues in the same way.
Your issue though is that you are not comparing like with like.
4.375 and 4.385 are not floats they are doubles and get converted to be stored so when you compare them later it's possible that the converted value is not quite identical. If you write 4.385f and 4.385f to use float values you should get YES both times.

Multiplying two floats doesn't give exact result

I am trying to multiply two floats as follows:
float number1 = 321.12;
float number2 = 345.34;
float rexsult = number1 * number2;
The result I want to see is 110895.582, but when I run the code it just gives me 110896. Most of the time I'm having this issue. Any calculator gives me the exact result with all decimals. How can I achive that result?
edit : It's C code. I'm using XCode iOS simulator.
There's a lot of rounding going on.
float a = 321.12; // this number will be rounded
float b = 345.34; // this number will also be rounded
float r = a * b; // and this number will be rounded too
printf("%.15f\n", r);
I get 110895.578125000000000 after the three separate roundings.
If you want more than 6 decimal digits' worth of precision, you will have to use double and not float. (Note that I said "decimal digits' worth", because you don't get decimal digits, you get binary.) As it stands, 1/2 ULP of error (a worst-case bound for a perfectly rounded result) is about 0.004.
If you want exactly rounded decimal numbers, you will have to use a specialized decimal library for such a task. A double has more than enough precision for scientists, but if you work with money everything has to be 100% exact. No floating point numbers for money.
Unlike integers, floating point numbers take some real work before you can get accustomed to their pitfalls. See "What Every Computer Scientist Should Know About Floating-Point Arithmetic", which is the classic introduction to the topic.
Edit: Actually, I'm not sure that the code rounds three times. It might round five times, since the constants for a and b might be rounded first to double-precision and then to single-precision when they are stored. But I don't know the rules of this part of C very well.
You will never get the exact result that way.
First of all, number1 ≠ 321.12 because that value cannot be represented exactly in a base-2 system. You'll need an infinite number of bits for it.
The same holds for number2 ≠ 345.34.
So, you begin with inexact values to begin with.
Then the product will get rounded because multiplication gives you double the number of significant digits but the product has to be stored in float again if you multiply floats.
You probably want to use a 10-based system for your numbers. Or, in case your numbers only have 2 decimal digits of the fractional, you can use integers (32-bit integers are sufficient in this case, but you may end up needing 64-bit):
32112 * 34534 = 1108955808.
That represents 321.12 * 345.34 = 110895.5808.
Since you are using C you could easily set the precision by using "%.xf" where x is the wanted precision.
For example:
float n1 = 321.12;
float n2 = 345.34;
float result = n1 * n2;
printf("%.20f", result);
Output:
110895.57812500000000000000
However, note that float only gives six digits of precision. For better precision use double.
floating point variables are only approximate representation, not precise one. Not every number can "fit" into float variable. For example, there is no way to put 1/10 (0.1) into binary variable, just like it's not possible to put 1/3 into decimal one (you can only approximate it with endless 0.33333)
when outputting such variables, it's usual to apply many rounding options. Unless you set them all, you can never be sure which of them are applied. This is especially true for << operators, as the stream can be told how to round BEFORE <<.
Printf also does some rounding. Consider http://codepad.org/LLweoeHp:
float t = 0.1f;
printf("result: %f\n", t);
--
result: 0.100000
Well, it looks fine. Why? Because printf defaulted to some precision and rounded up the output. Let's dial in 50 places after decimal point: http://codepad.org/frUPOvcI
float t = 0.1f;
printf("result: %.50f\n", t);
--
result: 0.10000000149011611938476562500000000000000000000000
That's different, isn't it? After 625 the float ran out of capacity to hold more data, that's why we see zeroes.
A double can hold more digits, but 0.1 in binary is not finite. Double has to give up, eventually: http://codepad.org/RAd7Yu2r
double t = 0.1;
printf("result: %.70f\n", t);
--
result: 0.1000000000000000055511151231257827021181583404541015625000000000000000
In your example, 321.12 alone is enough to cause trouble: http://codepad.org/cgw3vUKn
float t = 321.12f;
printf("and the result is: %.50f\n", t);
result: 321.11999511718750000000000000000000000000000000000000
This is why one has to round up floating point values before presenting them to humans.
Calculator programs don't use floats or doubles at all. They implement decimal number format. eg:
struct decimal
{
int mantissa; //meaningfull digits
int exponent; //number of decimal zeroes
};
Ofc that requires reinventing all operations: addition, substraction, multiplication and division. Or just look for a decimal library.

Why is not a==0 in the following code?

#include <stdio.h>
int main( )
{
float a=1.0;
long i;
for(i=0; i<100; i++)
{
a = a - 0.01;
}
printf("%e\n",a);
}
Result is: 6.59e-07
It's a binary floating point number, not a decimal one - therefore you need to expect rounding errors. See the Basic section in this article:
What Every Programmer Should Know About Floating-Point Arithmetic
For example, the value 0.01 does not have a precise represenation in binary floating point type. To get a "correct" result in your sample you would have to either round or use a a decimal floating point type (see Wikipedia):
Binary fixed-point types are most commonly used, because the rescaling operations can be implemented as fast bit shifts. Binary fixed-point numbers can represent fractional powers of two exactly, but, like binary floating-point numbers, cannot exactly represent fractional powers of ten. If exact fractional powers of ten are desired, then a decimal format should be used. For example, one-tenth (0.1) and one-hundredth (0.01) can be represented only approximately by binary fixed-point or binary floating-point representations, while they can be represented exactly in decimal fixed-point or decimal floating-point representations. These representations may be encoded in many ways, including BCD.
There are two questions here. If you're asking, why is my printf statement displaying the result as 6.59e-07 instead of 0.000000659, it's because you've used the format specifier for Scientific Notation: %e. You want %f for the floating point a.
printf("%f\n",a);
If you're asking why the result is not exactly zero rather than 0.000000659, the answer is (as others have pointed out) that with floating point arithmetic using binary numbers you need to expect rounding.
You have to specify %f for printing the float number then it will print 0 for variable a.
That's floating point numbers rounding errors on the scene. Each time you subtract a fraction you get approximately the result you'd normally expect from a number on paper and so the final result is very close to zero, but not necessarily precise zero.
The precision with floating numbers isn't accurate, that's why you find this result.
Cordially

Resources