简体   繁体   中英

Printf a double

I have a problem in printing a double in C.

My code:

#include <stdio.h>

main() {
   double n;
   scanf("%lf", &n);
   printf("%f", n);
}

input: 446486416781684178

output: 446486416781684160

Why does the number change?

The number you entered can't be represented exactly in a double .

Typically, a double is represented using IEEE754 double precision format. This format can hold up to 53 bits of precision. The value you entered requires 58 bits of precision. So what is stored is either the next or the previous representable value.

Why does the number change?

It got rounded off, because type double has finite precision.

We're used to roundoff happening to the right of the decimal point. If we write

double d = 0.123456789012345678;
printf("%.18f\n", d);

we are not too surprised if it prints

0.123456789012345677

Type double has the equivalent of about 16 decimal digit's worth of precision (actually it's more complicated than that), so it definitely can't represent all 18 digits of that number 0.123456789012345678.

But your number 446486416781684178 also has 18 significant digits, so we can't be too surprised that it can't be represented exactly, either. In other words, roundoff can happen to the left of the decimal point, also.

Internally, type double can represent numbers with 53 bits of precision. That means it can represent integers up to 2 53 , or 9007199254740992, with perfect accuracy. But bigger than that — it just can't. It can represent 900..,992. and it can represent 900..,994. but if you try to do 900..,993. it gets rounded back down to 900...992, If we look at the binary representations of these and nearby numbers: we can see why:

Decimal Binary Rep?
9007199254740990 11111111111111111111111111111111111111111111111111110 yes
9007199254740991 11111111111111111111111111111111111111111111111111111 yes
9007199254740992 100000000000000000000000000000000000000000000000000000 yes
9007199254740993 100000000000000000000000000000000000000000000000000001 no
9007199254740994 100000000000000000000000000000000000000000000000000010 yes

Since we only have 53 bits of significance, for a 54-bit number like 9007199254740992 or 9007199254740994, the 54th bit has to be 0, which basically means we can only represent even numbers in that range. The 54-bit number 9007199254740993 ends with a 1 bit, so it can't be exactly represented, which I've indicated with a "no" in the "Rep" ("exactly representable") column.

When we get up to a 59-bit number like 446486416781684178, the last six bits have to be 0, which means we can only represent numbers which are a multiple of 2 6 , or 64:

Decimal Binary Rep?
446486416781684160 1100011001000111101…001101010011110010110111000000 yes
446486416781684161 1100011001000111101…001101010011110010110111000001 no
... ... ...
446486416781684177 1100011001000111101…001101010011110010110111010001 no
446486416781684178 1100011001000111101…001101010011110010110111010010 no
446486416781684179 1100011001000111101…001101010011110010110111010011 no
... ... ...
446486416781684223 1100011001000111101…001101010011110010110111111111 no
446486416781684224 1100011001000111101…001101010011110010111000000000 yes

The number changes because of the limited precision of the double type. If you don't need floating point values, you could use type long long which is defined to have at least 63 value bits and can represent the number in the question.

Note that it is highly unlikely that the output be 446486416781684160 , the printf("%f", n) call should produce 446486416781684160.000000 . If your program does not produce 6 decimal places, your compiler and/or standard library are not conforming.

Also note that the main function should be defined with an explicit return type of int . The implicit int style has been deprecated more than 20 years ago.

Here is a modified version:

#include <stdio.h>

int main() {
    long long n;
    if (scanf("%lld", &n) == 1) {
        printf("%lld\n", n);
    }
    return 0;
}

Input: 446486416781684178
Output: 446486416781684178

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM