24

I am trying to print some floating point numbers using printf. For example:

int main()
{
    printf("%.1f",76.75); 
    return 0;
}

Output: 76.8

And I have some questions about the result.

First of all, why didn't it print 76.7?

Second, how did it round the number?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Malic Of Sdom
  • 431
  • 1
  • 3
  • 10
  • 7
    why it should print 76.7? – Jayesh Bhoi Jun 09 '14 at 13:04
  • 4
    @ecatmur: The answers to that question blame floating-point rounding errors, but this is a different situation because the number `76.75` is represented exactly. – dan04 Jun 09 '14 at 13:09
  • FWIW, your caption is: "Why (does) printf round floating point numbers?". Well, because you tell it to, with the `%.1f` formatting string. – Rudy Velthuis Jun 09 '14 at 16:43
  • @dan04: They don't *blame* rounding *errors*, they say it is the result of rounding. The answers explain how the value is rounded to one decimal digit, as specified in the format string. – Rudy Velthuis Jun 09 '14 at 16:46
  • 2
    @RudyVelthuis That question is “Why does `37.975` not convert to 37.98?”. This question is “Why does `76.75` convert to 76.8?”. They are symmetrically opposed questions. Besides, the answers there blame rounding in the **decimal-to-floating-point** conversion that happened during the compilation of `37.975`. The correct answer here should explain that this is the normal rounding behavior of **floating-point-to-decimal** conversion for a value that is exactly midway between two decimal representations. – Pascal Cuoq Jun 09 '14 at 17:02
  • @Pascal: I don't quite understand. What (other) question is what? It must have been deleted, I guess. The question here is clear, and the answers do not put blame on anything. I don't see any comment by someone called ecatmur either. – Rudy Velthuis Jun 09 '14 at 17:07
  • 2
    @Pascal: I see it now: the close vote. No, it is not a duplicate, IMO. – Rudy Velthuis Jun 09 '14 at 17:08

3 Answers3

19

C99 §7.19.6.1 The fprintf function

f,F

A double argument representing a floating-point number is converted to decimal notation in the style [−]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is zero and the # flag is not specified, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.

Community
  • 1
  • 1
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    Ah, but what does "rounded" mean? One might naïvely think that it means "to the nearest", with some wiggle room around 0.5, but note that the C standard defines four different rounding modes (ref 7.6) and the core standard declines to specify a default, so it isn't clear which one of them "rounded" refers to. If you believe that it follows the rounding mode (which the standard does not require), then deep in the weeds you find F.7.3 (C99, F.8.3 in C11 and C17), which specifies that the default rounding mode is "to nearest". – Jordan Brown Sep 03 '22 at 00:45
15

In addition to existing answers, note that many C compilers try to follow IEEE 754 for floating-point matters. IEEE 754 recommends rounding according to the current rounding mode for conversions from binary floating-point to decimal. The default rounding mode is “round to nearest and ties to even”. Some compilation platforms do not take the rounding mode into account and always round according to the default nearest-even mode in conversions from floating-point to decimal.

Since 76.75 represents the number 7675/100 exactly, it is precisely halfway between 76.7 and 76.8. The latter number is considered the “even” one when applying “round to nearest-even”. This is probably why your compilation platform chose to generate this decimal representation as the conversion to decimal of the floating-point number 76.75.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • I've never seen `printf` round according to the current rounding mode. (I haven't looked in years, though. All I saw was round-to-even and round-to-Java.) Which implementations do that? – tmyklebu Jun 09 '14 at 16:39
  • 2
    @tmyklebu Mac OS X. Linux always rounds to nearest-even, even if the rounding mode was changed. http://pastebin.com/p3myWBQU (obtained on Mac OS X). Microsoft's compiler has bigger problems than the rounding direction, so I don't think anyone cares about that. – Pascal Cuoq Jun 09 '14 at 16:46
  • 2
    @tmyklebu: always willing to learn something new, so what on earth is round-to-Java? Do you have a link? – Rudy Velthuis Jun 09 '14 at 17:12
  • @RudyVelthuis: As I recall, it always rounds "1/2" up. Namely, `System.out.printf("%.2f", 0.745);` outputs `0.75`, even though the `double `0.745` is strictly less than the rational number `745/1000`. – tmyklebu Jun 09 '14 at 23:44
  • @tmyklebu This is a bad example as `0.745` is not exact. Or perhaps it is a good example of the “Java rounding”, because Java prints it as exact with `%.53f`. So “Java rounding” would actually appear to be “print as many decimals as required to make the value unambiguous in the origin floating-point type, then apply the rounding rule from primary school”. `0.745` is less than 745/1000 and gets rounded to 0.75. Brilliant! Anyway, if you do not wish to get into the discussion of why Java is , a better example is `0.25`. – Pascal Cuoq Jun 10 '14 at 13:04
  • @PascalCuoq: That's why I picked `0.745`, actually. `0.745`-the-double is less than `0.745`-the-rational, so, printing with `"%.2f"`, it ought to be rounded down under any variation of round-to-nearest. But Java rounds it **up** with `"%.2f"`. – tmyklebu Jun 10 '14 at 17:38
  • @tmyklebu yes, the SEP shield is strong with this java rounding thing. Although the details were already in your first comment, I had to rediscover them. It is actually unbelievable enough that my brain edited out the info upon reading your previous comment. – Pascal Cuoq Jun 12 '14 at 21:29
  • @PascalCuoq: Sorry to put you through that. – tmyklebu Jun 12 '14 at 21:35
  • Actually, contrary to one of your comments, Linux's glibc rounds according to current rounding mode as of glibs-2.23, although it used to round to nearest unconditionally in 2.14.1 (the two versions I checked). See http://coliru.stacked-crooked.com/a/690aa6172119e241 for the former. – Ruslan Mar 16 '18 at 19:52
  • @Ruslan This is good to know, but please note that any comment I wrote, I wrote in 2014. If I had known that the situation was subject to change according to time in addition to changing according to platform, I would probably have described the situation as “a mess”, which was true then and is true now. – Pascal Cuoq Mar 16 '18 at 21:09
8

First of all, why he didn't print 76.7?

Because the language specification says that the low-order digit will be rounded.

how he rounded the number? (some code would help)

This differs implementation-by-implementation. According to the documentation,

The low-order digit shall be rounded in an implementation-defined manner (emphasis added).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523