How do I restrict a float value to only two places after the decimal point in C?

前端 未结 17 2726
孤城傲影
孤城傲影 2020-11-22 03:22

How can I round a float value (such as 37.777779) to two decimal places (37.78) in C?

相关标签:
17条回答
  • 2020-11-22 03:25
    double f_round(double dval, int n)
    {
        char l_fmtp[32], l_buf[64];
        char *p_str;
        sprintf (l_fmtp, "%%.%df", n);
        if (dval>=0)
                sprintf (l_buf, l_fmtp, dval);
        else
                sprintf (l_buf, l_fmtp, dval);
        return ((double)strtod(l_buf, &p_str));
    
    }
    

    Here n is the number of decimals

    example:

    double d = 100.23456;
    
    printf("%f", f_round(d, 4));// result: 100.2346
    
    printf("%f", f_round(d, 2));// result: 100.23
    
    0 讨论(0)
  • 2020-11-22 03:25

    Let me first attempt to justify my reason for adding yet another answer to this question. In an ideal world, rounding is not really a big deal. However, in real systems, you may need to contend with several issues that can result in rounding that may not be what you expect. For example, you may be performing financial calculations where final results are rounded and displayed to users as 2 decimal places; these same values are stored with fixed precision in a database that may include more than 2 decimal places (for various reasons; there is no optimal number of places to keep...depends on specific situations each system must support, e.g. tiny items whose prices are fractions of a penny per unit); and, floating point computations performed on values where the results are plus/minus epsilon. I have been confronting these issues and evolving my own strategy over the years. I won't claim that I have faced every scenario or have the best answer, but below is an example of my approach so far that overcomes these issues:

    Suppose 6 decimal places is regarded as sufficient precision for calculations on floats/doubles (an arbitrary decision for the specific application), using the following rounding function/method:

    double Round(double x, int p)
    {
        if (x != 0.0) {
            return ((floor((fabs(x)*pow(double(10.0),p))+0.5))/pow(double(10.0),p))*(x/fabs(x));
        } else {
            return 0.0;
        }
    }
    

    Rounding to 2 decimal places for presentation of a result can be performed as:

    double val;
    // ...perform calculations on val
    String(Round(Round(Round(val,8),6),2));
    

    For val = 6.825, result is 6.83 as expected.

    For val = 6.824999, result is 6.82. Here the assumption is that the calculation resulted in exactly 6.824999 and the 7th decimal place is zero.

    For val = 6.8249999, result is 6.83. The 7th decimal place being 9 in this case causes the Round(val,6) function to give the expected result. For this case, there could be any number of trailing 9s.

    For val = 6.824999499999, result is 6.83. Rounding to the 8th decimal place as a first step, i.e. Round(val,8), takes care of the one nasty case whereby a calculated floating point result calculates to 6.8249995, but is internally represented as 6.824999499999....

    Finally, the example from the question...val = 37.777779 results in 37.78.

    This approach could be further generalized as:

    double val;
    // ...perform calculations on val
    String(Round(Round(Round(val,N+2),N),2));
    

    where N is precision to be maintained for all intermediate calculations on floats/doubles. This works on negative values as well. I do not know if this approach is mathematically correct for all possibilities.

    0 讨论(0)
  • 2020-11-22 03:29

    Assuming you're talking about round the value for printing, then Andrew Coleson and AraK's answer are correct:

    printf("%.2f", 37.777779);
    

    But note that if you're aiming to round the number to exactly 37.78 for internal use (eg to compare against another value), then this isn't a good idea, due to the way floating point numbers work: you usually don't want to do equality comparisons for floating point, instead use a target value +/- a sigma value. Or encode the number as a string with a known precision, and compare that.

    See the link in Greg Hewgill's answer to a related question, which also covers why you shouldn't use floating point for financial calculations.

    0 讨论(0)
  • 2020-11-22 03:29

    ...or you can do it the old-fashioned way without any libraries:

    float a = 37.777779;
    
    int b = a; // b = 37    
    float c = a - b; // c = 0.777779   
    c *= 100; // c = 77.777863   
    int d = c; // d = 77;    
    a = b + d / (float)100; // a = 37.770000;
    

    That of course if you want to remove the extra information from the number.

    0 讨论(0)
  • 2020-11-22 03:32

    How about this:

    float value = 37.777779;
    float rounded = ((int)(value * 100 + .5) / 100.0);
    
    0 讨论(0)
  • 2020-11-22 03:34

    If you just want to round the number for output purposes, then the "%.2f" format string is indeed the correct answer. However, if you actually want to round the floating point value for further computation, something like the following works:

    #include <math.h>
    
    float val = 37.777779;
    
    float rounded_down = floorf(val * 100) / 100;   /* Result: 37.77 */
    float nearest = roundf(val * 100) / 100;  /* Result: 37.78 */
    float rounded_up = ceilf(val * 100) / 100;      /* Result: 37.78 */
    

    Notice that there are three different rounding rules you might want to choose: round down (ie, truncate after two decimal places), rounded to nearest, and round up. Usually, you want round to nearest.

    As several others have pointed out, due to the quirks of floating point representation, these rounded values may not be exactly the "obvious" decimal values, but they will be very very close.

    For much (much!) more information on rounding, and especially on tie-breaking rules for rounding to nearest, see the Wikipedia article on Rounding.

    0 讨论(0)
提交回复
热议问题