In C programming, using the modulo operator % works seamlessly for integer types (int, long, short). However, attempting to calculate the remainder of two floating-point numbers (float or double) using % results in a compilation error: invalid operands to binary %.
To compute the floating-point remainder of division in C, standard C library provides fmod(), fmodf(), and fmodl() in <math.h>. In this article, we explain the mathematics behind fmod(), compare it with remainder(), and demonstrate compiler usage with GCC.
Quick Code Reference: fmod() Syntax
Include <math.h> and link the math library with -lm during GCC compilation:
#include <stdio.h>
#include <math.h>
int main(void) {
double numerator = 18.5;
double denominator = 4.2;
// Calculate floating-point remainder: fmod(18.5, 4.2)
double remainder = fmod(numerator, denominator);
printf("Remainder of %.2f / %.2f = %.2f
", numerator, denominator, remainder);
// Output: Remainder of 18.50 / 4.20 = 1.70
return 0;
}# Compile C program linking math library (-lm)
gcc -O2 quick_reference.c -lm -o quick_reference
./quick_reference1. Why Modulo % Fails for Floating-Point Numbers
The % modulo operator is strictly defined for integer operands in the ISO C standard (C99/C11/C17). If you write 5.5 % 2.1, the GCC compiler rejects it immediately:
#include <stdio.h>
int main(void) {
float a = 9.7f;
float b = 3.2f;
// COMPILER ERROR: invalid operands to binary % (have 'float' and 'float')
// float rem = a % b;
return 0;
}2. Complete C fmod() Program with Precision Variants (main.c)
This program demonstrates remainder calculations across 32-bit float, 64-bit double, and 80/128-bit long double types while checking for division by zero (NaN):
#include <stdio.h>
#include <math.h>
#include <errno.h>
int main(void) {
printf("====================================================
");
printf(" C FLOATING-POINT REMAINDER DEMONSTRATION
");
printf("====================================================
");
// 1. Double Precision (64-bit fmod)
double x1 = 25.75, y1 = 5.2;
double rem1 = fmod(x1, y1);
printf("[double] fmod(%.2f, %.2f) = %.4f
", x1, y1, rem1);
// Math logic: 25.75 - (4 * 5.2) = 25.75 - 20.8 = 4.95
// 2. Single Precision (32-bit fmodf)
float x2 = 14.8f, y2 = 3.5f;
float rem2 = fmodf(x2, y2);
printf("[float] fmodf(%.2ff, %.2ff) = %.4f
", x2, y2, rem2);
// Math logic: 14.8 - (4 * 3.5) = 14.8 - 14.0 = 0.8
// 3. Extended Precision (long double fmodl)
long double x3 = 123.456L, y3 = 10.5L;
long double rem3 = fmodl(x3, y3);
printf("[long double] fmodl(%.3Lf, %.3Lf) = %.4Lf
", x3, y3, rem3);
// 4. Negative Numerator Handling
double x4 = -18.5, y4 = 4.2;
double rem4 = fmod(x4, y4);
printf("[negative] fmod(%.2f, %.2f) = %.2f
", x4, y4, rem4);
// 5. Handling Edge Cases: Division by Zero
double zero_divisor = 0.0;
errno = 0;
double invalid_rem = fmod(10.0, zero_divisor);
if (isnan(invalid_rem)) {
printf("Division by zero result: NaN (Not a Number)
");
}
if (errno == EDOM) {
printf("Domain Error (EDOM) set by math library.
");
}
return 0;
}fmod() vs remainder(): Mathematical Difference
`fmod(x, y)` (Truncated Division): Calculates
x - n * ywherenistrunc(x / y)(quotient truncated toward zero). The sign of the result matches the sign ofx.`remainder(x, y)` (Rounded Division - IEEE 754): Calculates
x - n * ywherenisrint(x / y)(quotient rounded to the nearest integer). Ifx / yis exactly half,nrounds to the nearest even integer.
Comments and corrections