Write your own implementation of math's floor function, C

darias picture darias · Jan 25, 2017 · Viewed 8k times · Source

I was thinking about the floor function available in math.h. It is very easy to use it:

#include <stdio.h>
#include <math.h>
 
int main(void)
{
  for (double a = 12.5; a < 13.4; a += 0.1)
    printf("floor of  %.1lf is  %.1lf\n", a, floor(a));
  return 0;
}

What if I would like to write my own implementation of it? Would it look simply like this:

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

double my_floor(double num)
{
    return (int)num;
}

int main(void)
{
    double a;

    for (a = 12.5; a < 13.4; a += 0.1)
        printf("floor of  %.1lf is  %.1lf\n", a, floor(a));

    printf("\n\n");

    for (a = 12.5; a < 13.4; a += 0.1)
        printf("floor of  %.1lf is  %.1lf\n", a, my_floor(a));

    return 0;
}

?

It seems it does not work with negative numbers (my_floor), but the second one seems to be fine (my_floor_2):

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

double my_floor(double num)
{
    return (int)num;
}

double my_floor_2(double num)
{
    if(num < 0)
        return (int)num - 1;
    else
        return (int)num;
}

int main(void)
{
    double a1 = -12.5;

    printf("%lf\n", floor(a1));
    printf("%lf\n", my_floor(a1));
    printf("%lf\n", my_floor_2(a1));

    return 0;
}

program output:

-13.000000
-12.000000
-13.000000

Is one of them eventually correct or not?

Answer

Bathsheba picture Bathsheba · Jan 25, 2017

No you can't tackle it this way. The best way of writing your own implementation is to steal the one from the C Standard Library on your platform. But note that might contain platform specific nuances so might not be portable.

The C Standard Library floor function is typically clever in that it doesn't work by taking a conversion to an integral type. If it did then you'd run the risk of signed integer overflow, the behaviour of which is undefined. (Note that the smallest possible range for an int is -32767 to +32767).

The precise implementation is also dependent on the floating point scheme used on your platform.

For a platform using IEEE754 floating point, and a long long type you could adopt this scheme:

  1. If the magnitude of the number is greater than the 53rd power of 2, return it back (as it's already integral).
  2. Else, cast to a 64 bit type (long long), and return it back.