简体   繁体   中英

How does printf in C round floating-point numbers?

I'm trying to implement printf and I want to know how printf rounds floating-point numbers because I cannot find a general rule

If for example input => printf("|%.f| |%.1f| |%.2f| |%.5f| |%.12f", 0.000099, 0.000099, 0.000099, 0.000099, 0.000099);

Here is the output => |0| |0.0| |0.00| |0.00010| |0.000099000000 |0| |0.0| |0.00| |0.00010| |0.000099000000

I use the method from IEEE-754 so our floating-point number in memory is: 0.000098999999999999994037755413067714016506215557456016540527343750

My question is when and how should I round my floating-point number?

I am looking for a general rule that I must follow for all floating-point numbers.

Not sure if this is exactly how printf does it, but this seems to work for your example:

Add 5/(10^(number of decimal points+1). Then truncate.

Your interpretation is flawed: Your C compiler is upcasting your constants to doubles. So it's not using 0.0000989999.... It's using the more accurate double equivalent.

Try this:

 printf("|%.f| |%.1f| |%.2f| |%.5f| |%.12f", (float)0.000099, (float)0.000099, (float)0.000099, (float)0.000099, (float)0.000099);

Output:

|0| |0.0| |0.00| |0.00010| |0.000098999997

The problem you are trying to address is actually very difficult to solve correctly.

Many existing printf implementations use conversion code dtoa.c written by David M. Gay almost 30 years ago.

You can learn more about this from this question, which is not an exact duplicate:

And these sites:

The C standard provides the following in §7.21.6.1p13:

For e, E, f, F, g, and G conversions, if the number of significant decimal digits is at most DECIMAL_DIG , then the result should be correctly rounded. If the number of significant decimal digits is more than DECIMAL_DIG but the source value is exactly representable with DECIMAL_DIG digits, then the result should be an exact representation with trailing zeros. Otherwise, the source value is bounded by two adjacent decimal strings L<U , both having DECIMAL_DIG significant digits; the value of the resultant decimal string D should satisfy L ≤ D ≤ U , with the extra stipulation that the error should have a correct sign for the current rounding direction.

However, that paragraph is part of a subsection headed "Recommended Practice". (If Annex F is in effect, then the recommended practice is required. See F.5.)

"Correctly rounded" is defined by the current rounding direction. See fsetround .

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