Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How am I incorrectly using the round() function in C?

Tags:

c

I'm getting unexpected results from the round() and roundf() functions in the math.h library. Here is the sample code:

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

int main(void)
{
    float f;
    double d;

    /* Note man page says that roundf() returns a float
       and round() returns a double */
    f = roundf(1.2);
    d = round(1.2);

    printf("%f\n", f);
    printf("%lf\n", d);

    return 0;
}

When I complie and run the program I get:

gcc -lm round.c
./a.out
288.000000
524288.000000

Wierd huh?

Update: Along with the answers I've confirmed that the code works properly on a newer complier. (I think %lf is not the correct printf specifier but that doesn't affect the end result in this case.) I'll need to figure out why may compiler is behaving this way because I have running code that uses round() and has been compiler on the same machine. I'll update the post when I figure it out.

gcc -v
Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/2.95.3/specs
gcc version 2.95.3 20010315 (release)
like image 668
Harry Avatar asked Feb 22 '09 22:02

Harry


People also ask

How does round function work in C?

The round( ) function in the C programming language provides the integer value that is nearest to the float, the double or long double type argument passed to it. If the decimal number is between “1 and. 5′′, it gives an integer number less than the argument.


1 Answers

You can fail if you compile the code without telling gcc to compile with C99 mode (-std=c99) and tell it not to know about "special builtin" functions (using -fno-builtin). Then it assumes that your round/roundf function is defined as

int round();
int roundf();

Because in pre-C99 times there were no such functions yet, so it does not have a declaration and implicitly declares them then. And this will obviously fail, because the call-side treats the return value as an int, while the callee side (in the definition of those functions in the linked library) returns a float. I get these results for example:

[js@HOST2 cpp]$ ./a.out
1065353216.000000
-1048576.000000
[js@HOST2 cpp]$

Not that you think now that you could cast the return value to a float and be OK. Well, it's worse. The return value is not even guaranteed to have anything to do with the float returned. The call-side reads from a place that it knows where integers are returned. But your compiler may return floats in another place (say, in a floating pointer register) from the callee side. The above could actually have done anything, including aborting the program because it behaves in an undefined manner.

So, what can you do to make it work? Pass the compiler the std=c99 flag or use other ways to round (floor is one of them) which do not require those functions

gcc -std=c99 test.c -lm

See the manpage of man 3 round. However, if you have a very old GCC - i'm not sure whether it supports enough of C99 to have that switch. Look into the feature test macros described in the manpage of round then.

like image 106
Johannes Schaub - litb Avatar answered Oct 15 '22 00:10

Johannes Schaub - litb