Mathematical Rounding and Remainder Functions in C
- The C standard mathematical library provides several functions to round floating-point numbers according to specific rules:
ceil,floor,trunc,round,nearbyintandrint. - The rounding functions can return the result as a floating-point value or as an integer value:
lroundandllround. - The C standard mathematical library also provides functions to calculate the remainder of division between floating-point numbers:
fmod,remainderandremquo.
Rounding Functions
The C standard mathematical library provides several functions to approximate floating-point numbers.
All these functions are declared in the <math.h> header.
We can divide these functions into three categories:
-
Functions that round a floating-point number upward or downward and return it as a floating-point value:
Function Description Notes double ceil(double x);Returns the smallest integer greater than or equal to x.double ceilf(float x);floatversion ofceil.C99 double ceill(long double x);long doubleversion ofceil.C99 double floor(double x);Returns the largest integer less than or equal to x.double floorf(float x);floatversion offloor.C99 double floorl(long double x);long doubleversion offloor.C99 Table 1: Ceil and floor functions of the standard mathematical library. The
ceilfunction and its variants return the smallest integer (in the form ofdouble) that is greater than or equal to the value passed as an argument. Indeed, the name "ceil" derives from the English word "ceiling", which means "ceiling" or "upper part".Conversely, the
floorfunction and its variants return the largest integer (in the form ofdouble) that is less than or equal to the value passed as an argument. The name "floor" derives from the English word "floor", which means "floor" or "lower part".Mathematically, we can express the behavior of these functions as follows:
For example:
ceil(4.2)returns5.0ceil(-4.2)returns-4.0floor(4.2)returns4.0floor(-4.2)returns-5.0
In other words, the
ceilfunction always rounds upward, while thefloorfunction always rounds downward. -
Functions that round a floating-point number always toward zero and return it as a floating-point value:
Function Description Notes double trunc(double x);Returns the integer part of x, rounded toward zero.C99 double truncf(float x);floatversion oftrunc.C99 double truncl(long double x);long doubleversion oftrunc.C99 Table 2: Trunc functions of the standard mathematical library. The
truncfunction and its variants return the integer part of the number passed as an argument, always rounded toward zero. For example:trunc(4.7)returns4.0trunc(-4.7)returns-4.0
In other words, the
truncfunction eliminates the decimal part of the number regardless of the sign of the number itself. Therefore,truncalways rounds toward zero.Indeed, we can express the behavior of this function as follows:
-
Functions that round a floating-point number away from zero and return it as a floating-point value:
Function Description Notes double round(double x);Returns the value of xrounded to the nearest integer. In case of tie, rounds away from zero.C99 double roundf(float x);floatversion ofround.C99 double roundl(long double x);long doubleversion ofround.C99 Table 3: Round functions of the standard mathematical library. The
roundfunction and its variants round the number passed as an argument to the nearest integer. In case of tie (when the decimal part is exactly 0.5), the function rounds away from zero. For example:round(4.5)returns5.0round(4.4)returns4.0round(-4.5)returns-5.0round(-4.4)returns-4.0
In other words, the
roundfunction follows the standard rounding rule, but in case of tie, it ensures that the result is always farther from zero.Indeed, we can express the behavior of this function as follows:
In addition to these functions that round according to specific rules, the library also provides functions to round a number according to the current rounding mode defined in the mathematical execution environment:
| Function | Description | Notes |
|---|---|---|
double nearbyint(double x); |
Returns the value of x rounded according to the current rounding mode. Does not raise overflow exceptions. |
C99 |
double nearbyintf(float x); |
float version of nearbyint. |
C99 |
double nearbyintl(long double x); |
long double version of nearbyint. |
C99 |
double rint(double x); |
Returns the value of x rounded according to the current rounding mode. May raise inexact or overflow exceptions. |
C99 |
double rintf(float x); |
float version of rint. |
C99 |
double rintl(long double x); |
long double version of rint. |
C99 |
These functions round the number passed as an argument according to the current rounding mode defined in the mathematical execution environment. The main difference between the two is that nearbyint does not raise overflow exceptions, while rint may raise inexact or overflow exceptions.
In practice, depending on the current rounding mode, these functions can behave like ceil, floor, trunc or round.
Integer Rounding Functions
The functions seen above round floating-point numbers to an integer according to specific rules, but still return a floating-point value.
The C standard mathematical library also provides functions that round floating-point numbers to an integer and return the result as an integer value.
| Function | Description | Notes |
|---|---|---|
long int lround(double x); |
Returns the value of x rounded to the nearest integer as long int. In case of tie, rounds away from zero. |
C99 |
long int lroundf(float x); |
float version of lround. |
C99 |
long int lroundl(long double x); |
long double version of lround. |
C99 |
long int llround(double x); |
Returns the value of x rounded to the nearest integer as long long int. In case of tie, rounds away from zero. |
C99 |
long int llroundf(float x); |
float version of llround. |
C99 |
long int llroundl(long double x); |
long double version of llround. |
C99 |
These functions behave similarly to the round function seen previously, rounding the number passed as an argument to the nearest integer. In case of tie, they round away from zero.
The difference, however, is that these functions return the result as an integer value (long int or long long int) instead of as a floating-point value.
For example:
lround(4.5)returns5lround(4.4)returns4llround(-4.5)returns-5llround(-4.4)returns-4
Remainder Function
In C language, there exists the modulo operator (or remainder operator) % which calculates the remainder of division between two integers.
However, it is not possible to apply the % operator directly to floating-point numbers. For this reason, the C standard mathematical library provides specific functions to calculate the remainder of division between two floating-point numbers.
| Function | Description | Notes |
|---|---|---|
double fmod(double x, double y); |
Returns the remainder of the division of x by y. |
|
double fmodf(float x, float y); |
float version of fmod. |
C99 |
double fmodl(long double x, long double y); |
long double version of fmod. |
C99 |
double remainder(double x, double y); |
Returns the remainder of the division of x by y, where the quotient has been rounded to the nearest integer. |
C99 |
double remainderf(float x, float y); |
float version of remainder. |
C99 |
double remainderl(long double x, long double y); |
long double version of remainder. |
C99 |
double remquo(double x, double y, int *quo); |
Identical to remainder but also saves the quotient in *quo. |
C99 |
double remquof(float x, float y, int *quo); |
float version of remquo. |
C99 |
double remquol(long double x, long double y, int *quo); |
long double version of remquo. |
C99 |
The functions of the fmod family calculate the remainder of the division of x by y according to the standard mathematical definition of modulo. For example, fmod(5.3, 2.0) returns 1.3, since 5.3 = 2.0 * 2 + 1.3.
The functions of the remainder family calculate the remainder of the division of x by y in a particular way. To understand how it works, let's define x divided by y, rounded to the nearest integer. The remainder function then returns the value:
For example, remainder(5.3, 2.0) returns -0.7, since the rounded quotient is 3 (the nearest integer to 5.3 / 2.0 = 2.65), and therefore 5.3 - 3 * 2.0 = -0.7. If we had used fmod(5.3, 2.0), we would have obtained 1.3.
The remquo function is similar to remainder, but additionally saves the rounded quotient in an integer passed as the third argument. This can be useful if you want to know both the remainder and the quotient of the division.
For example:
#include <stdio.h>
#include <math.h>
int main() {
double x = 5.3;
double y = 2.0;
int quo;
double r1 = fmod(x, y);
double r2 = remainder(x, y);
double r3 = remquo(x, y, &quo);
printf("fmod(%.1f, %.1f) = %.1f\n", x, y, r1);
printf("remainder(%.1f, %.1f) = %.1f\n", x, y, r2);
printf("remquo(%.1f, %.1f) = %.1f, quo = %d\n", x, y, r3, quo);
return 0;
}
The output will be:
fmod(5.3, 2.0) = 1.3
remainder(5.3, 2.0) = -0.7
remquo(5.3, 2.0) = -0.7, quo = 3