You could re-invent the wheel, as many other answers suggest. Alternately, you could use someone else's wheel -- I'd suggest Newlib's, which is BSD-licensed and intended for use on embedded systems. It properly handles negative numbers, NaNs, infinities, and cases which are not representable as integers (due to being too large), as well as doing so in an efficient manner that uses exponents and masking rather than generally-costlier floating-point operations. In addition, it's regularly tested, so you know it doesn't have glaring corner-case bugs in it.
The Newlib source can be a bit awkward to navigate, so here are the bits you want:
Float version: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/sf_round.c;hb=master
Double version: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/s_round.c;hb=master
Word-extraction macros defined here: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/fdlibm.h;hb=master
If you need other files from there, the parent directory is this one: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=tree;f=newlib/libm/common;hb=master
For the record, here's the code for the float version. As you can see, there's a bit of complexity required to deal with all the possible cases correctly.
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
Answer from Brooks Moses on Stack OverflowYou could re-invent the wheel, as many other answers suggest. Alternately, you could use someone else's wheel -- I'd suggest Newlib's, which is BSD-licensed and intended for use on embedded systems. It properly handles negative numbers, NaNs, infinities, and cases which are not representable as integers (due to being too large), as well as doing so in an efficient manner that uses exponents and masking rather than generally-costlier floating-point operations. In addition, it's regularly tested, so you know it doesn't have glaring corner-case bugs in it.
The Newlib source can be a bit awkward to navigate, so here are the bits you want:
Float version: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/sf_round.c;hb=master
Double version: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/s_round.c;hb=master
Word-extraction macros defined here: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/fdlibm.h;hb=master
If you need other files from there, the parent directory is this one: https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=tree;f=newlib/libm/common;hb=master
For the record, here's the code for the float version. As you can see, there's a bit of complexity required to deal with all the possible cases correctly.
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
int round(double x)
{
if (x < 0.0)
return (int)(x - 0.5);
else
return (int)(x + 0.5);
}
I have a question when it comes to rounding in C. Does it round up or down at .5? If it does round up, then does that mean that the smallest value of k in the code below can only be 1?
int main()
{
int k = 13;
int i;
for (i = 0; i < 8; i++) {
printf("%d", (k%2));
k >>= 1;
}
printf("%n");
}rounding - How to round floating point numbers to the nearest integer in C? - Stack Overflow
Rounding ints without round()
microcontroller - Round off Float value in C without in-built functions - Stack Overflow
Rounding in C
Videos
To round a float in C, there are 3 <math.h> functions to meet the need. Recommend rintf().
float nearbyintf(float x);
The
nearbyintfunctions 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
rintfunctions differ from thenearbyintfunctions (7.12.9.3) only in that therintfunctions 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
roundfunctions 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
numhave a value not near theintrange, the cast(int)results in undefined behavior.When
num +/- 0.5results in an inexact answer. This is unlikely here as0.5is adoublecausing the addition to occur at a higher precision thanfloat. Whennumand0.5have the same precision, adding0.5to 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.5results in an exact answer between 1.0 and the smallestdoublejust 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.
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:~$
Hey! First of all I know a bit about programming I started CS50x to extend my knowledge at lower level CS. When I approach labs and psets I always try to only use knowledge that was passed through the lecture by David.
When I started week 4 - filter (more) pset I had huge problem rounding RGB values of pixels, I had it off by 1 in a lot of cases and I knew it is rounding problem. I found round() function in math.h library but not sure if it was ever mentioned and if I'm using it I'm not cheating because in a lot of cases I could find a lot of helpful libraries but I always try to use default ones provided in .c files.
The usual solution on microcontrollers is to not do this. Decimal places are for humans, and that sort of luxury doesn't belong on embedded hardware. Heck, even binary floating point is a bit of a luxury.
The only place where you might see decimal math is in I/O operations. For those cases, it's easiest to internally work with an integer. So the range 0.0 - 6553.5 is internally represented as 0-65535. On output, you just print value/10 . value%10.
The standard way to do this is to scale, add 0.5, truncate, and un-scale:
float x;
...
x *= 10;
x = (int)(x + 0.5);
x /= 10;
Or, in one line:
x = (int)(x * 10 + 0.5) / 10.;
By adding 0.5 before truncating to int, you arrange that numbers with a fractional part greater than 0.5 round up.
But there are two other points to consider:
This simple, basic rounding recipe will not handle negative numbers correctly.
Floating-point numbers on most computers can't represent decimal fractions exactly. So you haven't really rounded
xto "one place past the decimal". If you printxout later, you'll often find that it seems to contain a number like, say, 3.199999 instead of 3.2. There's nothing you can do about this; the usual solution is to use a printf format like%.1fwhen it comes time to print the number out. And once you're using a printf format like%.1f, it'll do all the rounding for you, so you don't have to.
So the question is, what are you actually doing with your floating-point numbers that they have to be rounded to "one place past the decimal"? Are you printing them out as a string, or doing something else with them? And if you're printing them out, are you using printf or something else?