Число округлений до 2 десятичных мест в C

Как я могу объединить float (например, 37.777779) до двух знаков после запятой (37.78) в C?

Ответ 1

Если вы просто хотите округлить число для целей вывода, то строка формата "%.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 */

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

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

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

Ответ 2

Использование %.2f в printf. Он печатает только 2 десятичных знака.

Пример:

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

Выход:

37.77

Ответ 3

Предполагая, что вы говорите о значении для печати, тогда Andrew Coleson и AraK ответят правильно:

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

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

См. ссылку в Greg Hewgill ответьте на соответствующий вопрос, в котором также рассказывается, почему вы не должны использовать с плавающей точкой для финансовых расчетов.

Ответ 4

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

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);

Ответ 5

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

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

char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);

Ответ 6

Не существует способа округлить float до другого float, потому что округленный float может быть не представимым (ограничение числа с плавающей запятой). Например, скажите, что вы округлены с 37.777779 по 37.78, но ближайший представимый номер равен 37.781.

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

Ответ 7

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

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);

Ответ 8

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

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

Пример:

float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;

Ответ 9

В С++ (или в 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 переменных в этой функции, но я оставляю их там, чтобы вы могли видеть логику. Есть, вероятно, более простые решения, но это хорошо работает для меня, тем более что это позволяет мне корректировать количество цифр после десятичной точки по мере необходимости.

Ответ 10

Используйте 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 of 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 of 1.129999995232...

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

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

Хотя "1.135" - "на полпути" между 1.13 и 1.14, при преобразовании в float значение 1.134999990463... и больше не "на полпути" , а ближе к 1.13, а неправильно до float из 1.139999985695... из-за более ограниченной точности float vs. double. Это неправильное значение может считаться правильным, в зависимости от целей кодирования.

Ответ 11

Для этого всегда используйте семейство функций printf. Даже если вы хотите получить значение как число с плавающей запятой, лучше всего использовать snprintf, чтобы получить округленное значение в виде строки, а затем проанализировать его с помощью 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;
}

Я говорю это потому, что подход, который показал в настоящее время получивший наибольшее количество голосов ответ и несколько других здесь -  умножение на 100, округление до ближайшего целого и последующее деление на 100 - имеет два недостатка:

  • Для некоторых значений он будет округляться в неправильном направлении, поскольку умножение на 100 изменяет десятичную цифру, определяющую направление округления, с 4 на 5 или наоборот, из-за неточности чисел с плавающей запятой
  • Для некоторых значений умножение, а затем деление на 100 не приводит к обратному циклу, а это означает, что даже если нет округления, конечный результат будет неправильным

Чтобы проиллюстрировать первый тип ошибки - иногда неправильное направление округления - попробуйте запустить эту программу:

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);
}

Вы увидите этот вывод:

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

Обратите внимание, что значение, с которого мы начали, было меньше 0,015, и поэтому математически правильный ответ при округлении до 2 десятичных разрядов составляет 0,01. Конечно, 0,01 не совсем точно представляется в виде двойного числа, но мы ожидаем, что наш результат будет двойным, ближайшим к 0,01. Использование snprintf дает нам этот результат, но использование round(100 * x) / 100 дает нам 0,02, что неправильно. Почему? Потому что 100 * x дает нам ровно 1,5 в результате. Таким образом, умножение на 100 меняет правильное направление на округление.

Чтобы проиллюстрировать второй тип ошибки - результат иногда ошибочен из-за того, что * 100 и / 100 не совсем противоположны друг другу - мы можем выполнить аналогичное упражнение с очень большим числом:

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);
}

Наш номер теперь даже не имеет дробной части; это целочисленное значение, только что сохраненное с типом double. Таким образом, результат после округления должен быть таким же, как мы начали, верно?

Если вы запустите программу выше, вы увидите:

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

Упс. Наш метод snprintf снова возвращает правильный результат, но подход "умножить-затем-округлить-затем-разделить" не удается. Это потому, что математически правильное значение 8631192423766613.0 * 100, 863119242376661300.0, не совсем точно представляется в виде двойного числа; самое близкое значение - 863119242376661248.0. Когда вы делите это обратно на 100, вы получаете 8631192423766612.0 - число, отличное от того, с которого вы начали.

Надеемся, что достаточная демонстрация того, что использование roundf для округления до числа десятичных разрядов нарушена, и что вы должны использовать snprintf вместо этого. Если вам это кажется ужасным взломом, возможно, вы будете уверены, что знаете, что это в основном то, что делает CPython.

Ответ 12

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));

}

Здесь n - число десятичных знаков

Пример:

double d = 100.23456;

printf("%f", f_round(d, 4));// result: 100.2346

printf("%f", f_round(d, 2));// result: 100.23

Ответ 13

Я сделал этот макрос для округления чисел с плавающей точкой. Добавьте это в свой заголовок/существо файла

#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c)))

Вот пример:

float x = ROUNDF(3.141592, 100)

х равен 3,14 :)

Ответ 14

Определение кода:

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

Результаты:

a = 8.000000
sqrt(a) = r = 2.828427
roundz(r,2) = 2.830000
roundz(r,3) = 2.828000
roundz(r,5) = 2.828430

Ответ 15

Попробуйте это. он даст двойной с двумя знаками после запятой.

                int ttt = round(value * 100);
                string str = to_string(ttt);
                str.insert (str.end()-2,1,'.');
                double temp = ::strtod(str.c_str(), 0);
                obPrinciple = temp;

Ответ 16

Позвольте мне сначала попытаться оправдать мою причину добавления еще одного ответа на этот вопрос. В идеальном мире округление на самом деле не имеет большого значения. Однако в реальных системах вам может потребоваться несколько проблем, которые могут привести к округлению, что может и не быть тем, что вы ожидаете. Например, вы можете выполнять финансовые расчеты, когда конечные результаты округляются и отображаются пользователям как 2 десятичных знака; эти же значения хранятся с фиксированной точностью в базе данных, которая может содержать более двух знаков после запятой (по разным причинам, нет оптимального количества мест для хранения... зависит от конкретных ситуаций, которые должна поддерживать каждая система, например, крошечных предметов, чьи цены представляют собой доли копейки за единицу); и вычисления с плавающей запятой выполняются с значениями, где результаты равны плюс/минус эпсилон. Я столкнулся с этими проблемами и развивал свою собственную стратегию на протяжении многих лет. Я не буду утверждать, что я столкнулся со всеми сценариями или получил лучший ответ, но ниже приведен пример моего подхода, который преодолевает эти проблемы:

Предположим, что 6 десятичных знаков считаются достаточной точностью для вычислений по поплавкам/удвоениям (произвольное решение для конкретного приложения) с использованием следующей функции/метода округления:

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;
    }
}

Округление до 2 десятичных знаков для представления результата может быть выполнено как:

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

Для val = 6.825 результат 6.83, как ожидалось.

Для val = 6.824999 результат 6.82. Здесь предположение состоит в том, что расчет привел в точности к 6.824999, а седьмое десятичное число - нулю.

Для val = 6.8249999 результат 6.83. 7-е число после запятой 9 в этом случае заставляет функцию Round(val,6) дать ожидаемый результат. Для этого случая может быть любое количество конечных 9 s.

Для val = 6.824999499999 результат 6.83. Округление до восьмого десятичного знака в качестве первого шага, т.е. Round(val,8), заботится о одном неприятном случае, когда вычисляемый результат с плавающей запятой вычисляется до 6.8249995, но внутренне представлен как 6.824999499999....

Наконец, пример из вопроса... val = 37.777779 приводит к 37.78.

Этот подход может быть далее обобщен как:

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

где N - точность, которая должна поддерживаться для всех промежуточных вычислений по поплавкам/удвоениям. Это работает и с отрицательными значениями. Я не знаю, является ли этот подход математически правильным для всех возможностей.

Ответ 17

... или вы можете сделать это старомодным способом без каких-либо библиотек:

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;

Это, конечно, если вы хотите удалить дополнительную информацию из номера.

Ответ 18

эта функция принимает число и точность и возвращает округленное число

float roundoff(float num,int precision)
{
      int temp=(int )(num*pow(10,precision));
      int num1=num*pow(10,precision+1);
      temp*=10;
      temp+=5;
      if(num1>=temp)
              num1+=10;
      num1/=10;
      num1*=10;
      num=num1/pow(10,precision+1);
      return num;
}

он преобразует число с плавающей запятой в int по левому сдвигу точки и проверяет более пяти условий.