0

I want to understand how C handles the loss of precision for floating point number.

Here's my simple code:

#include <stdio.h>
#include <math.h>

int main ()
{
    double a;
    int i;
    i = 7;
    a = sqrt(i);

    printf("i = %d, a = %lf\n", i, a); 
    printf("a * a = %lf\n", a*a);

    a = 2.645751;
    printf("a * a = %lf\n", a*a);

    return(0);
}

Following is the result after cc

i = 7, a = 2.645751

a * a = 7.000000

a * a = 6.999998

If directly assigned a floating number which is 2.645751, the result of a * a looks understandable to me.

But if a is assigned sqrt(7), why there is no loss of precision for the output of a * a?

That is hard for me to understand.

2 Answers2

6

Your confusion comes from what is actually held in a and what is printed as the default precision by printf. From man 3 printf "If the precision is missing, it is taken as 6". Therefore when you print with %lf (which should be simply %f as %f is already the format specifier for double) you are only seeing the value of a to the default 6-digit precision. (rounded)

a does not contain 2.645751 following your call to a = sqrt(i); -- that is just the default precision output by your printf statement. You can clearly see this just by specifying a longer precision for the output, e.g.

printf("i = %d, a = %.10f\n", i, a); 

Output:

i = 7, a = 2.6457513111

So you need to keep clear what is contained in the actual double is most likely not what you see when you use printf with the default format specifier and default precision. double values (the 64-bits) represent a 1-bit sign bit, an 11-bit normalized exponent and a 52-bit mantissa. Not all numbers are capable of being represented exactly (just due to the limitation of bits to represent every possible number).

A good, but arguably rather dry to read, reference that goes into this a bit further is What Every Programmer Should Know About Floating-Point

Let me know if this helped your understanding, or whether you still have questions. We are happy to help further.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • For general C questions, it is preferable to cite the C standard rather than the POSIX/Unix/other man pages. The citation for the default of 6 digits could be C 2011 7.21.6.1 8. – Eric Postpischil Jan 01 '18 at 01:25
  • That is exactly what I inartfully attempted to explain. Feel free to take creative license with the wording. (the boss arrived and I had to help with groceries) – David C. Rankin Jan 01 '18 at 01:26
  • @iBug, you know, I'm just a simple man. All I can do is read. `man 3 printf` states `"f, F The double argument is rounded and converted to decimal notation in the style [-]ddd.ddd"`, so you may be right in your doubt, but all I can do is read. – David C. Rankin Jan 01 '18 at 01:51
  • @DavidC.Rankin Fine. I was wrong. – iBug Jan 01 '18 at 01:53
  • Happens to me all the time `:)` – David C. Rankin Jan 01 '18 at 01:56
  • FYI `%.53f` should be sufficient to see the exact value of a `double` at this scale. – R.. GitHub STOP HELPING ICE Jan 01 '18 at 04:33
  • @R To add: `"%.52e"` should be sufficient to see the exact value of a `double` at _any_ scale - if `printf()` is robust. An easy alternative to see the exact value is to use `"%a"` - of course the significand is hexadecimal then. – chux - Reinstate Monica Jan 01 '18 at 16:33
0

Your assigned a as double that have very long precision then the precision you assigned as hard coded. Thus, the precision error you got with the hard coded numbers is visible. At the same time, the precision error with sqrt() is not that much to visible, though it is not fully displayed with the printf().

Richard
  • 56,349
  • 34
  • 180
  • 251
Md Monjur Ul Hasan
  • 1,705
  • 1
  • 13
  • 36