My code is
void main()
{
float a = 0.7;
if (a < 0.7)
printf("c");
else
printf("c++");
}
It prints C and this is fine as a treated as double constant value and its value will be 0.699999 which is less than 0.7.
Now if I change the value to 0.1,0.2,0.3 till 0.9 in a and also at if condition then it prints C++, apart from 0.7 and 0.9 that mean both are equal or a is greater.
Why this concept not consider for all value?
What "concept" are you talking about?
None of the numbers you mentioned are representable precisely in binary floating-point format (regardless of precision). All of the numbers you mentioned end up having infinite number of binary digits after the dot.
Since neither float nor double have infinite precision, in float and double formats the implementation will represent these values approximately, most likely by a nearest representable binary floating-point value. These approximate values will be different for float and double. And the approximate float value might end up being greater or smaller than the approximate double value. Hence the result you observe.
For example in my implementation, the value of 0.7 is represented as
+6.9999998807907104e-0001 - float
+6.9999999999999995e-0001 - double
Meanwhile the value of 0.1 is represented as
+1.0000000149011611e-0001 - float
+1.0000000000000000e-0001 - double
As you can see, double representation is greater than float representation in the first example, while in the second example it is the other way around. (The above are decimal notations, which are rounded by themselves, but they do have enough precision to illustrate the effect well enough.)
Related
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.
I have such a program
int a = 100;
float b = 1.05;
printf("%f\n", a * b);
printf("%f\n", 100 * 1.05);
Its output looks like this:
104.999992
105.000000
I understand that `104.99992' is due to floating-point precision issues. But why does the use of direct numbers not result in a loss of accuracy?
a * b uses float arithmetic. 100 * 1.05 uses double arithmetic.
Your C implementation probably uses IEEE-754 binary64 for double and binary32 for float.
1.05 is a double constant. The decimal numeral 1.05 in source text is converted to the nearest representable double value, which is 4728779608739021•2−52 = 1.0500000000000000444089209850062616169452667236328125.
float b = 1.05; converts that value to float. The result of the conversion is the nearest representable float value, which is 4728779393990656•2−52 = 4404019•2−22 = 1.0499999523162841796875.
When b is multiplied by 100 in float arithmetic, the result is the representable float value that is nearest the real-arithmetic result. It is 13762559•2−17 = 104.99999237060546875.
When that is printed with six digits after the decimal point, the result is “104.999992”.
In 100 * 1.05, only double arithmetic is used; there are no float values. When the double 1.0500000000000000444089209850062616169452667236328125 is multiplied by 100, the result is the double nearest the real-arithmetic result. It is 105•20 = 105. When that is printed with six digits after the decimal point, the result is of course “105.000000”.
Summary: There are generally rounding errors in floating-point arithmetic. In float arithmetic, they are easily visible when more than a few digits are printed. In this example with double arithmetic, the rounding errors happened to cancel—the double nearest 1.05 was slightly above 1.05, so the rounding in the conversion rounded up. Then, when that was multiplied by 100, the double nearest the real-arithmetic result was slightly below it, so the rounding in the multiplication rounded down. These effectively canceled, producing 105.
If you execute printf("%f\n", 100*1.05f);, 1.05f will be converted directly to float instead of to a double, and the multiplication will be done with float arithmetic,1 and you will see the same result as for a * b.
Footnote
1 The C standard allows extra precision to be used, but generally you will see the same result here.
This question already has answers here:
Is floating point math broken?
(31 answers)
Identical float values comparing as inequal [duplicate]
(4 answers)
Closed 3 years ago.
The program below outputs This No. is not same. Why does it do this when both numbers are the same?
void main() {
float f = 2.7;
if(f == 2.7) {
printf("This No. is same");
} else {
printf("This No. is not same");
}
}
Why does it do this when both numbers are the same?
The numbers are not the same value.
double can represent exactly typically about 264 different values.
float can represent exactly typically about 232 different values.
2.7 is not one of the values - some approximations are made given the binary nature of floating-point encoding versus the decimal text 2.7
The compiler converts 2.7 to the nearest representable double or
2.70000000000000017763568394002504646778106689453125
given the typical binary64 representation of double.
The next best double is
2.699999999999999733546474089962430298328399658203125.
Knowing the exact value beyond 17 significant digits has reduced usefulness.
When the value is assigned to a float, it becomes the nearest representable float or
2.7000000476837158203125.
2.70000000000000017763568394002504646778106689453125 does not equal 2.7000000476837158203125.
Should a compiler use a float/double which represents 2.7 exactly like with decimal32/decimal64, code would work as OP expected. double representation using an underlying decimal format is rare. Far more often the underlying double representation is base 2 and these conversion artifacts need to be considered when programming.
Had the code been float f = 2.5;, the float and double value, using a binary or decimal underlying format, would have made if (f == 2.5) true. The same value as a high precision double is representable exactly as a low precision float.
(Assuming binary32/binary64 floating point)
double has 53 bits of significance and float has 24. The key is that if the number as a double has its least significant (53-24) bits set to 0, when converted to float, it will have the same numeric value as a float or double. Numbers like 1, 2.5 and 2.7000000476837158203125 fulfill that. (range, sub-normal, and NaN issues ignored here.)
This is a reason why exact floating point comparisons are typically only done in select situations.
Check this program:
#include<stdio.h>
int main()
{
float x = 0.1;
printf("%zu %zu %zu\n", sizeof(x), sizeof(0.1), sizeof(0.1f));
return 0;
}
Output is 4 8 4.
The values used in an expression are considered as double (double precision floating point format) unless a f is specified at the end. So the expression “x==0.1″ has a double on right side and float which are stored in a single precision floating point format on left side.
In such situations float is promoted to double .
The double precision format uses uses more bits for precision than single precision format.
In your case add 2.7f to get expected result.
The literal 2.7 in f == 2.7 is converted to double that's why 2.7 is not equal to f.
float a = 0.7;
if(a<0.7)
printf("true");
else
printf("false");
OUTPUT : true
Now , if I change the value of a to say 1.7 ,then
float a = 1.7;
if(a<1.7)
printf("true");
else
printf("false");
OUTPUT : false
Since 0.7 is treated as a double (HIGH PRECISION) and a is a float (LESS PRECISION) , therefore a < 0.7 , and in second case it should be the same again , so it should also print true. Why the difference in output here ?
PS : I have already seen this link.
Since you saw my answer to the question you linked, let's work through it and make the necessary changes to examine your second scenario:
In binary, 1.7 is:
b1.1011001100110011001100110011001100110011001100110011001100110...
However, 1.7 is a double-precision literal, whose value is 1.7 rounded to the closest representable double-precision value, which is:
b1.1011001100110011001100110011001100110011001100110011
In decimal, that's exactly:
1.6999999999999999555910790149937383830547332763671875
When you write float a = 1.7, that double value is rounded again to single-precision, and a gets the binary value:
b1.10110011001100110011010
which is exactly
1.7000000476837158
in decimal (note that it rounded up!)
When you do the comparison (a < 1.7), you are comparing this single-precision value (converted to double, which does not round, because all single-precision values are representable in double precision) to the original double-precision value. Because
1.7000000476837158 > 1.6999999999999999555910790149937383830547332763671875
the comparison correctly returns false, and your program prints "false".
OK, so why are the results different with 0.7 and 1.7? It's all in the rounding. Single-precision numbers have 24 bits. When we write down 0.7 in binary, it looks like this:
b.101100110011001100110011 00110011...
(there is space after the 24th bit to show where it is). Because the next digit after the 24th bit is a zero, when we round to 24 bits, we round down.
Now look at 1.7:
b1.10110011001100110011001 10011001...
because we have the leading 1., the position of the 24th bit shifts, and now the next digit after the 24th bit is a one, and we round up instead.
If float and double are IEEE-754 32 bit and 64 bit floating point formats respectively, then the closest float to exactly 1.7 is ~1.7000000477, and the closest double is ~1.6999999999999999556. In this case the closest float just happens to be numerically greater than the closest double.
0.7 and 1.7 aren't represented the same way in base-2 - so the one might be slightly more and the other slightly fewer than the actual (exact) value.
It all has to do with base 2 representation of floating-point. Here is a good reference about the subject: What Every Computer Scientist Should Know About Floating-Point Arithmetic.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Difference between float and double
strange output in comparision of float with float literal
I am using visual C++ 6.0 and in a program I am comparing float and double variables
For example for this program
#include<stdio.h>
int main()
{
float a = 0.7f;
double b = 0.7;
printf("%d %d %d",a<b,a>b,a==b);
return 0;
}
I am getting 1 0 0 as output
and for
#include<stdio.h>
int main()
{
float a = 1.7f;
double b = 1.7;
printf("%d %d %d",a<b,a>b,a==b);
return 0;
}
I am getting 0 1 0 as output.
Please tell me why I am getting these weird output and is there any way to predict these outputs on the same processor. Also how comparison is done of two variables in C ?
It has to do with the way the internal representation of floats and doubles are in the computer. Computers store numbers in binary which is base 2. Base 10 numbers when stored in binary may have repeating digits and the "exact" value stored in the computer is not the same.
When you compare floats, it's common to use an epsilon to denote a small change in values. For example:
float epsilon = 0.000000001;
float a = 0.7;
double b = 0.7;
if (abs(a - b) < epsilon)
// they are close enough to be equal.
1.7d and 1.7f are very likely to be different values: one is the closest you can get to the absolute value 1.7 in a double representation, and one is the closest you can get to the absolute value 1.7 in a float representation.
To put it into simpler-to-understand terms, imagine that you had two types, shortDecimal and longDecimal. shortDecimal is a decimal value with 3 significant digits. longDecimal is a decimal value with 5 significant digits. Now imagine you had some way of representing pi in a program, and assigning the value to shortDecimal and longDecimal variables. The short value would be 3.14, and the long value would be 3.1416. The two values aren't the same, even though they're both the closest representable value to pi in their respective types.
1.7 is decimal. In binary, it has non-finite representation.
Therefore, 1.7 and 1.7f differ.
Heuristic proof: when you shift bits to the left (ie multiply by 2) it will in the end be an integer if ever the binary representation is “finite”.
But in decimal, multiply 1.7 by 2, and again: you will only obtain non-integers (decimal part will cycle between .4, .8, .6 and .2). Therefore 1.7 is not a sum of powers of 2.
You can't compare floating point variables for equality. The reason is that decimal fractions are represented as binary ones, that means loss of precision.