Videos
Both of your attempts have limitations:
- If the
doublevalue is outside the range of theinttype, converting tointis implementation defined. - If the
doublevalue is negative but integral, returning(int)num - 1is incorrect.
Here is an (almost) portable version that tries to handle all cases:
double my_floor_2(double num) {
if (num >= LLONG_MAX || num <= LLONG_MIN || num != num) {
/* handle large values, infinities and nan */
return num;
}
long long n = (long long)num;
double d = (double)n;
if (d == num || num >= 0)
return d;
else
return d - 1;
}
It should be correct if type long long has more value bits than type double, which is the case on most modern systems.
No, you can't tackle it this way. The best way of writing your own implementation is to take 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:
- If the magnitude of the number is greater than 253, return it (as it's already integral).
- Else, cast to a 64-bit type (
long long), and return it back.
The easiest solution would probably be to just let C do it. Per ยง 6.3.1.4 of the C11 spec:
When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero).
So, all you need to do is convert the value to an integer, than convert that back to a float:
float myFloor(float value) {
return (float) (int) value;
}
If you need to handle negatives, you can easily do so:
float myFloor(float value) {
float tmp = (float) (int) value;
return (tmp != value) ? (tmp - 1.0f) : tmp;
}
One way is to convert-
float myFloor(float value) {
return (float) (int) value;
}
but 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:
- If the magnitude of the number is greater than the 53rd power of 2, return it back (as it's already integral).
- Else, cast to a 64 bit type (long long), and return it back.