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.
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:~$
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 thenearbyint
functions (7.12.9.3) only in that therint
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))
Should
num
have a value not near theint
range, the cast(int)
results in undefined behavior.When
num +/- 0.5
results in an inexact answer. This is unlikely here as0.5
is adouble
causing the addition to occur at a higher precision thanfloat
. Whennum
and0.5
have the same precision, adding0.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, yetnum + 0.5
results in an exact answer between 1.0 and the smallestdouble
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.
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.
A general solution is to use rint() and set the FLT_ROUNDS rounding mode as appropriate.
I think what you're looking for is:
int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d);
the googled code works correctly. The idea behind it is that you round down when the decimal is less than .5 and round up otherwise. (int)
casts the float into a int type which just drops the decimal. If you add .5 to a positive num, you get drop to the next int. If you subtract .5 from a negative it does the same thing.
You may be able to use fesetround()
in fenv.h
(introduced in C99). The possible arguments are the macros FE_DOWNWARD
, FE_TONEAREST
, FE_TOWARDZERO
, and FE_UPWARD
but note that not all of them are necessarily defined - only the ones supported by the platform/implementation are. Then you can use the various round
, rint
and nearbyint
functions in math.h
(also C99). This way you can set the desired rounding behaviour once and call the same function regardless of whether or not the value is positive or negative.
(With e.g. lround
you usually need not even set the rounding direction for normal use to usually get what you want.)
int round(double x)
{
return x >= 0.0 ? int(x + 0.5) : int(x - int(x-1) + 0.5) + int(x-1);
}
It will be faster, than a version with ceil and floor.
Round value x to precision p, where 0 < p < infinite. (f.ex. 0.25, 0.5, 1, 2,…)
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;
}
just add 0.5 to the number and typecast it.. and print it by type casting it in integer.. otherwise you can go with round() inside which just pass the argument as the respective number.
Try moving the brackets on your solution above, so that it reads:
(int)(num < 0) ? (num - 0.5) : (num + 0.5)
Using num as 4.9 it rounds to 5 on my machine.
精彩评论