Округление числа до 2 десятичных знаков в C - PullRequest
190 голосов
/ 28 августа 2009

Как можно округлить число с плавающей запятой (например, 37,777779) до двух десятичных знаков (37,78) в C?

Ответы [ 16 ]

378 голосов
/ 28 августа 2009

Если вы просто хотите округлить число для целей вывода, тогда строка формата "%.2f" действительно является правильным ответом. Однако, если вы действительно хотите округлить значение с плавающей запятой для дальнейших вычислений, работает что-то вроде следующего:

#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 */

Обратите внимание, что есть три различных правила округления, которые вы можете выбрать: округление вниз (т.е. усечение после двух десятичных разрядов), округление до ближайшего и округление в большую сторону. Обычно вы хотите округлить до ближайшего.

Как отметили некоторые другие, из-за причуд представления с плавающей запятой, эти округленные значения могут быть не совсем "очевидными" десятичными значениями, но они будут очень и очень близки.

Для получения гораздо (намного!) Дополнительной информации о округлении, и особенно о правилах разрыва связей для округления до ближайшего, см. статью Википедии о округлении .

67 голосов
/ 28 августа 2009
printf("%.2f", 37.777779);
40 голосов
/ 28 августа 2009

Если вы говорите о значении для печати, то Эндрю Колесон и AraK ответ правильный:

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

Но обратите внимание, чтоесли вы хотите округлить число до 37,78 для внутреннего использования (например, сравнить с другим значением), то это не очень хорошая идея из-за способа работы чисел с плавающей запятой: обычно вы этого не хотитеСравнения равенства для чисел с плавающей запятой, вместо этого используйте целевое значение +/- сигма-значение.Или закодируйте число в виде строки с известной точностью и сравните ее.

См. Ссылку в Ответ Грега Хьюгилла на связанный вопрос , в котором также объясняется, почему не следует использовать плавающеепункт для финансовых расчетов.

23 голосов
/ 28 августа 2009

Как насчет этого:

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);
19 голосов
/ 28 августа 2009
printf("%.2f", 37.777779);

Если вы хотите записать в C-строку:

char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);
11 голосов
/ 28 августа 2009

Нет способа округлить float до другого float, потому что округленное float может быть не представимым (ограничение чисел с плавающей точкой). Например, допустим, вы округлили с 37,777779 до 37,78, но ближайшее представимое число - 37,781.

Однако вы можете"округлить" float, используя функцию форматирования строки.

8 голосов
/ 23 августа 2013

Кроме того, если вы используете C ++, вы можете просто создать такую ​​функцию:

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

Затем вы можете вывести любые двойные myDouble с n местами после десятичной точки с кодом, например, таким:

std::cout << prd(myDouble,n);
7 голосов
/ 28 августа 2009

Вы все еще можете использовать:

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

пример:

float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;
6 голосов
/ 22 августа 2012

В C ++ (или в C с приведением в стиле C) вы можете создать функцию:

/* Function to control # of decimal places to be output for x */
double showDecimals(const double& x, const int& numDecimals) {
    int y=x;
    double z=x-y;
    double m=pow(10,numDecimals);
    double q=z*m;
    double r=round(q);

    return static_cast<double>(y)+(1.0/m)*r;
}

Тогда std::cout << showDecimals(37.777779,2); даст: 37,78.

Очевидно, вам не нужно создавать все 5 переменных в этой функции, но я оставляю их там, чтобы вы могли видеть логику. Возможно, есть более простые решения, но это хорошо работает для меня, особенно потому, что позволяет мне настраивать количество цифр после десятичного знака, как мне нужно.

4 голосов
/ 03 августа 2014

Использование float roundf(float x).

"Функции округления округляют свой аргумент до ближайшего целочисленного значения в формате с плавающей запятой, округляя полпути до нуля, независимо от текущего направления округления." C11dr §7.12.9.5

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

В зависимости от вашей реализации float числа, которые могут показаться наполовину, не являются. поскольку плавающая точка обычно ориентирована на базу-2. Кроме того, точное округление до ближайшего 0.01 во всех «промежуточных» случаях является наиболее сложным.

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

Хотя «1,115» находится «на полпути» между 1,11 и 1,12, при преобразовании в float значение равно 1.115000009537... и больше не «на полпути», а ближе к 1.12 и округляется до ближайшего float из 1.120000004768...

«1,125» означает «на полпути» между 1,12 и 1,13, при преобразовании в float значение в точности равно 1.125 и «на полпути». Он округляется до 1,13 из-за связи с четным правилом и округляется до ближайшего float из 1.129999995232...

Хотя «1.135» находится «на полпути» между 1,13 и 1,14, при преобразовании в float значение равно 1.134999990463... и больше не «на полпути», а ближе к 1,13 и округляется до ближайшего float из 1.129999995232...

Если используется код

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

Хотя «1.135» находится «на полпути» между 1,13 и 1,14, при преобразовании в float значение равно 1.134999990463... и больше не «на полпути», но ближе к 1,13, но неправильно округляет до float из 1.139999985695... из-за более ограниченной точности float против double. Это неправильное значение может рассматриваться как правильное в зависимости от целей кодирования.

...