Rounding Number to 2 Decimal Places in C

2020-01-22 11:19发布

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

18条回答
男人必须洒脱
2楼-- · 2020-01-22 11:55

Also, if you're using C++, you can just create a function like this:

string prd(const double x, const int decDigits) {
    stringstream ss;
    ss << fixed;
    ss.precision(decDigits); // set # places after decimal
    ss << x;
    return ss.str();
}

You can then output any double myDouble with n places after the decimal point with code such as this:

std::cout << prd(myDouble,n);
查看更多
闹够了就滚
3楼-- · 2020-01-22 11:56

You can still use:

float ceilf(float x); // don't forget #include <math.h> and link with -lm.

example:

float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;
查看更多
叼着烟拽天下
4楼-- · 2020-01-22 11:57

How about this:

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);
查看更多
手持菜刀,她持情操
5楼-- · 2020-01-22 11:58

Always use the printf family of functions for this. Even if you want to get the value as a float, you're best off using snprintf to get the rounded value as a string and then parsing it back with atof:

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

double dround(double val, int dp) {
    int charsNeeded = 1 + snprintf(NULL, 0, "%.*f", dp, val);
    char *buffer = malloc(charsNeeded);
    snprintf(buffer, charsNeeded, "%.*f", dp, val);
    double result = atof(buffer);
    free(buffer);
    return result;
}

I say this because the approach shown by the currently top-voted answer and several others here - multiplying by 100, rounding to the nearest integer, and then dividing by 100 again - is flawed in two ways:

  • For some values, it will round in the wrong direction because the multiplication by 100 changes the decimal digit determining the rounding direction from a 4 to a 5 or vice versa, due to the imprecision of floating point numbers
  • For some values, multiplying and then dividing by 100 doesn't round-trip, meaning that even if no rounding takes place the end result will be wrong

To illustrate the first kind of error - the rounding direction sometimes being wrong - try running this program:

int main(void) {
    // This number is EXACTLY representable as a double
    double x = 0.01499999999999999944488848768742172978818416595458984375;

    printf("x: %.50f\n", x);

    double res1 = dround(x, 2);
    double res2 = round(100 * x) / 100;

    printf("Rounded with snprintf: %.50f\n", res1);
    printf("Rounded with round, then divided: %.50f\n", res2);
}

You'll see this output:

x: 0.01499999999999999944488848768742172978818416595459
Rounded with snprintf: 0.01000000000000000020816681711721685132943093776703
Rounded with round, then divided: 0.02000000000000000041633363423443370265886187553406

Note that the value we started with was less than 0.015, and so the mathematically correct answer when rounding it to 2 decimal places is 0.01. Of course, 0.01 is not exactly representable as a double, but we expect our result to be the double nearest to 0.01. Using snprintf gives us that result, but using round(100 * x) / 100 gives us 0.02, which is wrong. Why? Because 100 * x gives us exactly 1.5 as the result. Multiplying by 100 thus changes the correct direction to round in.

To illustrate the second kind of error - the result sometimes being wrong due to * 100 and / 100 not truly being inverses of each other - we can do a similar exercise with a very big number:

int main(void) {
    double x = 8631192423766613.0;

    printf("x: %.1f\n", x);

    double res1 = dround(x, 2);
    double res2 = round(100 * x) / 100;

    printf("Rounded with snprintf: %.1f\n", res1);
    printf("Rounded with round, then divided: %.1f\n", res2);
}

Our number now doesn't even have a fractional part; it's an integer value, just stored with type double. So the result after rounding it should be the same number we started with, right?

If you run the program above, you'll see:

x: 8631192423766613.0
Rounded with snprintf: 8631192423766613.0
Rounded with round, then divided: 8631192423766612.0

Oops. Our snprintf method returns the right result again, but the multiply-then-round-then-divide approach fails. That's because the mathematically correct value of 8631192423766613.0 * 100, 863119242376661300.0, is not exactly representable as a double; the closest value is 863119242376661248.0. When you divide that back by 100, you get 8631192423766612.0 - a different number to the one you started with.

Hopefully that's a sufficient demonstration that using roundf for rounding to a number of decimal places is broken, and that you should use snprintf instead. If that feels like a horrible hack to you, perhaps you'll be reassured by the knowledge that it's basically what CPython does.

查看更多
甜甜的少女心
6楼-- · 2020-01-22 12:01

Code definition :

#define roundz(x,d) ((floor(((x)*pow(10,d))+.5))/pow(10,d))

Results :

a = 8.000000
sqrt(a) = r = 2.828427
roundz(r,2) = 2.830000
roundz(r,3) = 2.828000
roundz(r,5) = 2.828430
查看更多
我命由我不由天
7楼-- · 2020-01-22 12:02

Use float roundf(float x).

"The round functions round their argument to the nearest integer value in floating-point format, rounding halfway cases away from zero, regardless of the current rounding direction." C11dr §7.12.9.5

#include <math.h>
float y = roundf(x * 100.0f) / 100.0f; 

Depending on your float implementation, numbers that may appear to be half-way are not. as floating-point is typically base-2 oriented. Further, precisely rounding to the nearest 0.01 on all "half-way" cases is most challenging.

void r100(const char *s) {
  float x, y;
  sscanf(s, "%f", &x);
  y = round(x*100.0)/100.0;
  printf("%6s %.12e %.12e\n", s, x, y);
}

int main(void) {
  r100("1.115");
  r100("1.125");
  r100("1.135");
  return 0;
}

 1.115 1.115000009537e+00 1.120000004768e+00  
 1.125 1.125000000000e+00 1.129999995232e+00
 1.135 1.134999990463e+00 1.139999985695e+00

Although "1.115" is "half-way" between 1.11 and 1.12, when converted to float, the value is 1.115000009537... and is no longer "half-way", but closer to 1.12 and rounds to the closest float of 1.120000004768...

"1.125" is "half-way" between 1.12 and 1.13, when converted to float, the value is exactly 1.125 and is "half-way". It rounds toward 1.13 due to ties to even rule and rounds to the closest float of 1.129999995232...

Although "1.135" is "half-way" between 1.13 and 1.14, when converted to float, the value is 1.134999990463... and is no longer "half-way", but closer to 1.13 and rounds to the closest float of 1.129999995232...

If code used

y = roundf(x*100.0f)/100.0f;

Although "1.135" is "half-way" between 1.13 and 1.14, when converted to float, the value is 1.134999990463... and is no longer "half-way", but closer to 1.13 but incorrectly rounds to float of 1.139999985695... due to the more limited precision of float vs. double. This incorrect value may be viewed as correct, depending on coding goals.

查看更多
登录 后发表回答