2

Strange output when I use float instead of double

#include <stdio.h>
void main()
{
    double p,p1,cost,cost1=30;
    for (p = 0.1; p < 10;p=p+0.1)
    {
        cost = 30-6*p+p*p;
        if (cost<cost1)
        {
            cost1=cost;
            p1=p;
        }
        else
        {
            break;
        }
        printf("%lf\t%lf\n",p,cost);
    }
    printf("%lf\t%lf\n",p1,cost1);
}

As Expected

Gives output as expected at p = 3;

But when I use float the output is a little weird.

#include <stdio.h>
void main()
{
    float p,p1,cost,cost1=40;
    for (p = 0.1; p < 10;p=p+0.1)
    {
        cost = 30-6*p+p*p;
        if (cost<cost1)
        {
            cost1=cost;
            p1=p;
        }
        else
        {
            break;
        }
        printf("%f\t%f\n",p,cost);
    }
    printf("%f\t%f\n",p1,cost1);
}

Strange increment style

Why is the increment of p in the second case going weird after 2.7?

14
  • 2
    Looks like a rounding error to me since float has fewer significant digits than a double. Commented Feb 14, 2015 at 5:12
  • 1
    I am just adding 0.1 to p . What is there for rounding in it ? Even if it is so why after 2.7 not before. Commented Feb 14, 2015 at 5:14
  • 4
    floating point types are the cats of numerical variables. No matter how you herd them they still do what they please. Commented Feb 14, 2015 at 5:17
  • 2
    The double is probably 2.799999999999 - with more 9's, so it still gets rounded to 2.8. Commented Feb 14, 2015 at 5:18
  • 3
    @ysaditya: floating-point-gui.de ... Commented Feb 14, 2015 at 6:42

2 Answers 2

12

This is happening because the float and double data types store numbers in base 2. Most base-10 numbers can’t be stored exactly. Rounding errors add up much more quickly when using floats. Outside of embedded applications with limited memory, it’s generally better, or at least easier, to use doubles for this reason.

To see this happening for double types, consider the output of this code:

#include <stdio.h>
int main(void)
{
    double d = 0.0;
    for (int i = 0; i < 100000000; i++)
        d += 0.1;
    printf("%f\n", d);
    return 0;
}

On my computer, it outputs 9999999.981129. So after 100 million iterations, rounding error made a difference of 0.018871 in the result.

For more information about how floating-point data types work, read What Every Computer Scientist Should Know About Floating-Point Arithmetic. Or, as akira mentioned in a comment, see the Floating-Point Guide.

Sign up to request clarification or add additional context in comments.

3 Comments

and i was trying around 500 and waiting for any difference
@ysaditya I was a bit surprised that it took so many iterations for the errors to add up. After one million iterations, the difference was only 0.000001.
it's generally better to use unsigned longs
6

Your program can work fine with float. You don't need double to compute a table of 100 values to a few significant digits. You can use double, and if you do, it will have chances to work even if you use binary floating-point binary at cross-purposes. The IEEE 754 double-precision format used for double by most C compilers is so precise that it makes many misuses of floating-point unnoticeable (but not all of them).

Values that are simple in decimal may not be simple in binary

A consequence is that a value that is simple in decimal may not be represented exactly in binary.

This is the case for 0.1: it is not simple in binary, and it is not represented exactly as either double or float, but the double representation has more digits and as a result, is closer to the intended value 1/10.

Floating-point operations are not exact in general

Binary floating-point operations in a format such as float or double have to produce a result in the intended format. This leads to some digits having to be dropped from the result each time an operation is computed. When using binary floating-point in an advanced manner, the programmer sometimes knows that the result will have few enough digits for all the digits to be represented in the format (in other words, sometimes a floating-point operation can be exact and advanced programmers can predict and take advantage of conditions in which this happens). But here, you are adding 0.1, which is not simple and (in binary) uses all the available digits, so most of the times, this addition is not be exact.

How to print a small table of values using only float

In for (p = 0.1; p < 10;p=p+0.1), the value of p, being a float, will be rounded at each iteration. Each iteration will be computed from a previous iteration that was already rounded, so the rounding errors will accumulate and make the end result drift away from the intended, mathematical value.

Here is a list of improvements over what you wrote, in reverse order of exactness:

for (i = 1, p = 0.1f; i < 100; i++, p = i * 0.1f)

In the above version, 0.1f is not exactly 1/10, but the computation of p involves only one multiplication and one rounding, instead of up to 100. That version gives a more precise approximation of i/10.

for (i = 1, p = 0.1f; i < 100; i++, p = i * 0.1)

In the very slightly different version above, i is multiplied by the double value 0.1, which more closely approximates 1/10. The result is always the closest float to i/10, but this solution is cheating a bit, since it uses a double multiplication. I said a solution existed with only float!

for (i = 1, p = 0.1f; i < 100; i++, p = i / 10.0f)

In this last solution, p is computed as the division of i, represented exactly as a float because it is a small integer, by 10.0f, which is also exact for the same reason. The only computation approximation is that of a single operation, and the arguments are exactly what we wanted them to, so this is the best solution. It produces the closest float to i/10 for all values of i between 1 and 99.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.