Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to round floating point numbers to the nearest integer in C?

Tags:

c

rounding

Is there any way to round numbers in C?

I do not want to use ceil and floor. Is there any other alternative?

I came across this code snippet when I Googled for the answer:

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

The above line always prints the value as 4 even when float num =4.9.

like image 962
webgenius Avatar asked Apr 03 '10 10:04

webgenius


People also ask

How do you round a float in C?

you can use #define round(a) (int) (a+0.5) as macro so whenever you write round(1.6) it returns 2 and whenever you write round(1.3) it return 1.

How do round to the nearest integer?

Rounding to the Nearest Integer If the digit in the tenths place is less than 5, then round down, which means the units digit remains the same; if the digit in the tenths place is 5 or greater, then round up, which means you should increase the unit digit by one.

How do you round up in C?

In the C Programming Language, the ceil function returns the smallest integer that is greater than or equal to x (ie: rounds up the nearest integer).


3 Answers

4.9 + 0.5 is 5.4, which cannot possibly round to 4 unless your compiler is seriously broken.

I just confirmed that the Googled code gives the correct answer for 4.9.

marcelo@macbookpro-1:~$ cat round.c 
#include <stdio.h>

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:~$
like image 162
Marcelo Cantos Avatar answered Oct 26 '22 21:10

Marcelo Cantos


To round a float in C, there are 3 <math.h> functions to meet the need. Recommend rintf().

float nearbyintf(float x);

The nearbyint functions round their argument to an integer value in floating-point format, using the current rounding direction and without raising the ‘‘inexact’’ floating point exception. C11dr §7.12.9.3 2

or

float rintf(float x);

The rint functions differ from the nearbyint functions (7.12.9.3) only in that the rint functions may raise the ‘‘inexact’’ floating-point exception if the result differs in value from the argument. C11dr §7.12.9.4 2

or

float roundf(float x);

The round functions round their argument to the nearest integer value in floating-point format, rounding halfway cases away from zero, regardless of the current rounding direction. C11dr §7.12.9.6 2


Example

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

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

Output

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

What is weak about OP's code?

(int)(num < 0 ? (num - 0.5) : (num + 0.5))
  1. Should num have a value not near the int range, the cast (int) results in undefined behavior.

  2. When num +/- 0.5 results in an inexact answer. This is unlikely here as 0.5 is a double causing the addition to occur at a higher precision than float. When num and 0.5 have the same precision, adding 0.5 to a number may result in numerical rounded answer. (This is not the whole number rounding of OP's post.) Example: the number just less than 0.5 should round to 0 per OP's goal, yet num + 0.5 results in an exact answer between 1.0 and the smallest double just less than 1.0. Since the exact answer is not representable, that sum rounds, typically to 1.0 leading to an incorrect answer. A similar situation occurs with large numbers.


OP's dilemma about "The above line always prints the value as 4 even when float num =4.9." is not explainable as stated. Additional code/information is needed. I suspect OP may have used 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;
  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
}

Tested little - will do so later when I have time.

like image 39
chux - Reinstate Monica Avatar answered Oct 26 '22 20:10

chux - Reinstate Monica


I'm not sure that's such a good idea. That code depends on casts, and I'm fairly sure that the exact truncation is undefined.

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

I'd say that this is a much better way (which is basically what Shiroko posted) since it doesn't depend on any casts.

like image 43
Puppy Avatar answered Oct 26 '22 20:10

Puppy