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

StackOverflow https://stackoverflow.com/questions/497018

  •  20-08-2019
  •  | 
  •  

Вопрос

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

значение с плавающей запятой = 45.592346543;

Я хотел бы округлить фактическое значение до одного знака после запятой, conver = 45.6.

Это было полезно?

Решение

Как упоминал Роб, вы, вероятно, просто хотите Печать значение с плавающей точкой до 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;
}

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

Другие советы

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

#include <math.h>

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

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

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

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

Редактировать:Кроме того, для поплавков вы можете использовать truncf() для усечения поплавков.Тот же самый прием + 0,5 должен сработать для точного округления.

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

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

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

Для Печать округленное значение, @Мэтт Джей хорошо отвечает на вопрос.

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,5 f, а затем используя 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;
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top