Как округлить числа с плавающей точкой до ближайшего целого числа в C?

Есть ли способ округлить числа в C?

Я не хочу использовать пол и пол. Есть ли другая альтернатива?

Я натолкнулся на этот fragment кода, когда я ответил Googled для ответа:

(int)(num < 0 ? (num - 0.5) : (num + 0.5)) 

Вышеприведенная строка всегда печатает значение как 4, даже если float num = 4.9.

4.9 + 0.5 – 5.4, что не может округлить до 4, если ваш компилятор серьезно не сломается.

Я только что подтвердил, что код Googled дает правильный ответ для 4.9.

 marcelo@macbookpro-1:~$ cat round.c #include  int main() { float num = 4.9; int n = (int)(num < 0 ? (num - 0.5) : (num + 0.5)); printf("%d\n", n); } marcelo@macbookpro-1:~$ make round && ./round cc round.c -o round 5 marcelo@macbookpro-1:~$ 

Общее решение – использовать rint () и установить режим округления FLT_ROUNDS, если это необходимо.

Я не уверен, что это такая хорошая идея. Этот код зависит от приведения, и я уверен, что точное усечение не определено.

 float result = (num - floor(num) > 0.5) ? ceil(num) : floor(num); 

Я бы сказал, что это намного лучший способ (в основном, то, что Широко опубликовал), поскольку он не зависит от каких-либо бросков.

Я думаю, что вы ищете: int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d); int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d);

код googled работает правильно. Идея этого заключается в том, что вы округлите, когда десятичное число меньше 0,5 и наоборот. (int) отбрасывает float в тип int, который просто делит десятичную. Если вы добавите .5 в положительное число, вы получите падение до следующего int. Если вы вычитаете .5 из отрицательного, то он делает то же самое.

Чтобы объединить float в C, существуют 3 функции для удовлетворения потребностей. Рекомендуем rintf() .

 float nearbyintf(float x); 

Функция nearbyint свой аргумент до целочисленного значения в формате с плавающей запятой, используя текущее направление округления и не поднимая «неточное» исключение с плавающей запятой. C11dr §7.12.9.3 2

или же

 float rintf(float x); 

Функции rint отличаются от nearbyint функций (7.12.9.3) только тем, что функции rint могут вызывать « rint исключение с плавающей точкой, если результат отличается по значению от аргумента. C11dr §7.12.9.4 2

или же

 float roundf(float x); 

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


пример

 #include  #include  #include  void rtest(const char *fname, double (*f)(double x), double x) { printf("Clear inexact flag :%s\n", feclearexcept(FE_INEXACT) ? "Fail" : "Success"); printf("Set round to nearest mode:%s\n", fesetround(FE_TONEAREST) ? "Fail" : "Success"); double y = (*f)(x); printf("%s(%f) --> %f\n", fname,x,y); printf("Inexact flag :%s\n", fetestexcept(FE_INEXACT) ? "Inexact" : "Exact"); puts(""); } int main(void) { double x = 8.5; rtest("nearbyint", nearbyint, x); rtest("rint", rint, x); rtest("round", round, x); return 0; } 

Выход

 Clear inexact flag :Success Set round to nearest mode:Success nearbyint(8.500000) --> 8.000000 Inexact flag :Exact Clear inexact flag :Success Set round to nearest mode:Success rint(8.500000) --> 8.000000 Inexact flag :Inexact Clear inexact flag :Success Set round to nearest mode:Success round(8.500000) --> 9.000000 Inexact flag :Exact 

Что слабого в коде OP?

 (int)(num < 0 ? (num - 0.5) : (num + 0.5)) 
  1. Если num имеет значение, не близкое к диапазону int , cast (int) приводит к неопределенному поведению.

  2. Когда num +/- 0.5 приводит к неточному ответу. Здесь маловероятно, что 0.5 является double приводит к тому, что добавление происходит с большей точностью, чем float . Когда num и 0.5 имеют одинаковую точность, добавление 0.5 к числу может привести к округленному числу. (Это не целое число округления сообщения OP.) Пример: число, равное менее 0,5, должно округляться до 0 для цели OP, но num + 0.5 дает точный ответ между 1.0 и самым маленьким double чуть меньше 1.0. Поскольку точный ответ не является представимым, эта сумма округляется, как правило, до 1.0, приводя к неправильному ответу. Аналогичная ситуация имеет место с большими числами.


Дилемма OP о «Вышеприведенная строка всегда печатает значение как 4, даже когда float num =4.9 ». не объяснимо, как указано. Требуется дополнительный код / ​​информация. Я подозреваю, что OP мог использовать int num = 4.9; ,


 // avoid all library calls // Relies on UINTMAX_MAX >= FLT_MAX_CONTINUOUS_INTEGER - 1 float my_roundf(float x) { // Test for large values of x // All of the x values are whole numbers and need no rounding #define FLT_MAX_CONTINUOUS_INTEGER (FLT_RADIX/FLT_EPSILON) if (x >= FLT_MAX_CONTINUOUS_INTEGER) return x; // Positive numbers // Important: _no_ precision lost in the subtraction // This is the key improvement over OP's method if (x > 0) { float floor_x = (float)(uintmax_t) x; if (x - floor_x >= 0.5) floor_x += 1.0f; return floor_x; } if (x < 0) return -my_roundf(-x); return x; // x is 0.0, -0.0 or NaN } 

Протестировано немного - сделаю это позже, когда у меня будет время.

Вы можете использовать fesetround() в fenv.h (представленный на C99). Возможными аргументами являются macros FE_DOWNWARD , FE_TONEAREST , FE_TOWARDZERO и FE_UPWARD но обратите внимание, что не все из них обязательно определены – только те, которые поддерживаются платформой / реализацией. Затем вы можете использовать различные функции round , rint и nearbyint в math.h (также C99). Таким образом, вы можете установить желаемое поведение округления один раз и вызвать ту же функцию независимо от того, является ли это значение положительным или отрицательным.

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

 int round(double x) { return x >= 0.0 ? int(x + 0.5) : int(x - int(x-1) + 0.5) + int(x-1); } 

Это будет быстрее, чем версия с потолком и полом.

Круглое значение x с точностью p, где 0

 float RoundTo(float x, float p) { float y = 1/p; return int((x+(1/(y+y)))*y)/y; } float RoundUp(float x, float p) { float y = 1/p; return int((x+(1/y))*y)/y; } float RoundDown(float x, float p) { float y = 1/p; return int(x*y)/y; } 

просто добавьте 0.5 к числу и приведите его к типу .. и напечатайте его по типу, введя его в целое число. В противном случае вы можете пойти с round () внутри, который просто передает аргумент как соответствующий номер.

Попробуйте переместить скобки на свое решение выше, чтобы он читал:

 (int)(num < 0) ? (num - 0.5) : (num + 0.5) 

Используя num как 4.9, он округляется до 5 на моей машине.