Есть ли функция для округления числа с плавающей точкой в ​​C или мне нужно написать свою собственную? - PullRequest
24 голосов
/ 30 января 2009

Есть ли функция для округления числа с плавающей точкой в ​​C или мне нужно написать свою собственную?

число с плавающей точкой = 45. 59 2346543;

Я хотел бы округлить фактическое значение до одного десятичного знака, конвертируем = 45. 6 .

Ответы [ 7 ]

28 голосов
/ 30 января 2009

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

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

int main()
{
  float conver = 45.592346543;
  printf("conver is %0.1f\n",conver);
  return 0;
}

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

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

int main()
{
  float conver = 45.592346543;
  printf("conver is %0.1f\n",conver);

  conver = conver*10.0f;
  conver = (conver > (floor(conver)+0.5f)) ? ceil(conver) : floor(conver);
  conver = conver/10.0f;

  //If you're using C99 or better, rather than ANSI C/C89/C90, the following will also work.
  //conver = roundf(conver*10.0f)/10.0f;

  printf("conver is now %f\n",conver);
  return 0;
}

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

28 голосов
/ 30 января 2009

Конечно, вы можете использовать roundf () . Если вы хотите округлить до одного десятичного знака, то вы можете сделать что-то вроде: roundf(10 * x) / 10

2 голосов
/ 30 января 2009
#include <math.h>

double round(double x);
float roundf(float x);

Не забудьте связать с -lm. Смотрите также ceil (), floor () и trunc ().

1 голос
/ 29 января 2016

К печать округленное значение, @ Matt J хорошо отвечает на вопрос.

float x = 45.592346543;
printf("%0.1f\n", x);  // 45.6

Поскольку большинство значений с плавающей запятой (FP) * двоичное на основе, точное округление до одного десятичное место невозможно, если математически правильный ответ равен x.1, x.2, ... .

Для преобразования числа FP в ближайший 0.1 это другой вопрос.

Переполнение : Подходы к тому, что первое масштабирование на 10 (или 100, 1000 и т. Д.) Может переполниться при большом x.

float round_tenth1(float x) {
  x = x * 10.0f;
  ...
}

Двойное округление : Добавление 0,5f и последующее использование floorf(x*10.0f + 0.5f)/10.0 возвращает неверный результат, когда промежуточная сумма x*10.0f + 0.5f округляется до нового целого числа.

// Fails to round 838860.4375 correctly, comes up with 838860.5 
// 0.4499999880790710449 fails as it rounds to 0.5
float round_tenth2(float x) {
  if (x < 0.0) {
    return ceilf(x*10.0f + 0.5f)/10.0f;
  }
  return floorf(x*10.0f + 0.5f)/10.0f;
}

Приведение к int имеет очевидную проблему, когда float x намного больше, чем INT_MAX.


Лучше всего использовать roundf() и семейство, доступное в <math.h>.

float round_tenthA(float x) {
  double x10 = 10.0 * x;
  return (float) (round(x10)/10.0);
}

Чтобы не использовать double, просто проверьте, нужно ли округлить число.

float round_tenthB(float x) {
  const float limit = 1.0/FLT_EPSILON;
  if (fabsf(x) < limit) {
    return roundf(x*10.0f)/10.0f;
  }
  return x;
}
1 голос
/ 22 мая 2014

Существует функция round(), также fround(), которая округляется до ближайшего целого числа, выраженного как двойное число. Но это не то, что вы хотите.

У меня была такая же проблема, и я написал это:

#include <math.h>

   double db_round(double value, int nsig)
/* ===============
**
** Rounds double <value> to <nsig> significant figures.  Always rounds
** away from zero, so -2.6 to 1 sig fig will become -3.0.
**
** <nsig> should be in the range 1 - 15
*/

{
    double     a, b;
    long long  i;
    int        neg = 0;


    if(!value) return value;

    if(value < 0.0)
    {
        value = -value;
        neg = 1;
    }

    i = nsig - log10(value);

    if(i) a = pow(10.0, (double)i);
    else  a = 1.0;

    b = value * a;
    i = b + 0.5;
    value = i / a;

    return neg ? -value : value;
} 
1 голос
/ 30 января 2009

Просто чтобы немного обобщить ответ Роба, если вы не делаете это на выходе, вы все равно можете использовать тот же интерфейс с sprintf().

Я думаю, что есть и другой способ сделать это. Вы можете попробовать ceil() и floor(), чтобы округлить вверх и вниз. Хорошая уловка - добавить 0,5, так что все, что больше 0,5, округляется вверх, а все, что под ним, округляется вниз. ceil() и floor() работают только на double с.

РЕДАКТИРОВАТЬ: Кроме того, для поплавков, вы можете использовать truncf() для усечения поплавков. Тот же трюк +0,5 должен работать для точного округления.

0 голосов
/ 15 апреля 2015

вы можете использовать #define round (a) (int) (a + 0.5) в качестве макроса поэтому, когда вы пишете раунд (1.6), он возвращает 2, а всякий раз, когда вы пишете раунд (1.3), он возвращает 1.

...