This error looks more mysterious than it is. GCC is pointing at %, calling it “binary,” and then listing two types in parentheses. Read that message literally: the operator has a left operand and a right operand, and at least one of them is not a type that % accepts.
Why the compiler rejects this expression
int main(void)
{
float value = 11.0f;
double divisor = 3.0;
double result = value % divisor;
return result == 0.0;
}The `%` expression is invalid because its operands are `float` and `double`.
Reading the types before reading the error
11.0fhas typefloatbecause of thefsuffix.3.0has typedouble; a decimal floating literal isdoubleunless a suffix changes it.%is a binary operator because it consumes two operands, but the C language restricts both operands to integer types.Changing the result variable to
intwould not help. The invalid operation occurs on the right side before assignment.
cc -std=c17 -Wall -Wextra -Wpedantic broken_remainder.c -o broken_remainderbroken_remainder.c: In function ‘main’:
broken_remainder.c:5:27: error: invalid operands to binary % (have ‘float’ and ‘double’)
5 | double result = value % divisor;
| ^What this compile step tells you
-std=c17selects the C17 language mode; the diagnostic is a language constraint, not a warning-level preference.-Wall -Wextra -Wpedanticadds useful diagnostics, but removing those flags will not make an invalid%expression legal.The caret points to the operator, while the parenthetical type list identifies the actual mismatch to investigate.
Choose the repair based on what the numbers mean
There are two honest fixes. Neither begins with a cast. First decide whether the program is modelling indivisible units—packets, array positions, students, bytes—or measured quantities such as distance, voltage, and elapsed time.
Whole counts belong in integer types
When fractions are impossible by definition, represent that fact in the type system. Then % expresses exactly the operation you intended.
#include <stdio.h>
int main(void)
{
int items = 11;
int group_size = 3;
int leftover = items % group_size;
printf("Complete groups: %d\n", items / group_size);
printf("Items left over: %d\n", leftover);
return 0;
}Use integer remainder when the domain consists of whole counts.
Why this version fits the domain
intcommunicates that partial items and fractional group sizes are not valid inputs.items / group_sizeperforms integer division and returns the number of complete groups.items % group_sizereturns2, the whole items that remain after forming three groups.Production code must still verify
group_size != 0before using either/or%.
Measured values need a floating-point remainder function
When the fractional part carries meaning, preserve it. The C math library provides a matching remainder function for each standard floating type.
fmodf(float x, float y)returnsfloat.fmod(double x, double y)returnsdouble.fmodl(long double x, long double y)returnslong double.
#include <math.h>
#include <stdio.h>
int main(void)
{
double distance = 11.5;
double lap_length = 3.0;
if (lap_length == 0.0) {
fprintf(stderr, "lap length must not be zero\n");
return 1;
}
double remainder = fmod(distance, lap_length);
printf("Distance after complete laps: %.2f\n", remainder);
return 0;
}Use `fmod` when the operands and the remainder may contain fractional values.
Small choices that keep the fix correct
<math.h>declaresfmod; calling it without the correct declaration is not a valid shortcut.Both arguments are
double, matching thefmodsignature and preserving the.5indistance.fmod(x, y)computesx - trunc(x / y) * y; its result has the sign ofxand magnitude smaller than|y|when defined.A zero divisor is a domain error for
fmod, so the example rejects it before making the call.
cc -std=c17 -Wall -Wextra -Wpedantic floating_remainder.c -lm -o floating_remainder
./floating_remainderDistance after complete laps: 2.50About the -lm at the end
-lmlinks the system math library on toolchains wherefmodis not linked automatically.Library order can matter with traditional Unix linkers, so place
-lmafter the source or object files that use it.The executable prints
2.50because three complete lap lengths account for9.0of the11.5distance.
Do not confuse fmod with remainder
The C library also has a function literally named remainder. It is not simply another spelling of fmod: it chooses its result using a quotient rounded to the nearest integer, while fmod uses a quotient truncated toward zero. For code being translated from %, fmod usually matches the intended remainder model more closely.
Floating-point “divisibility” needs a tolerance
Many decimal fractions cannot be represented exactly in binary floating point. As a result, testing fmod(value, step) == 0.0 can reject a value that is mathematically a multiple. A tolerance must reflect the scale and error budget of your application; there is no universal epsilon.
#include <float.h>
#include <math.h>
#include <stdbool.h>
bool is_approximately_multiple(double value, double step)
{
if (!isfinite(value) || !isfinite(step) || step <= 0.0) {
return false;
}
double r = fmod(value, step);
double scale = fmax(fabs(value), fabs(step));
double tolerance = 8.0 * DBL_EPSILON * scale;
return fabs(r) <= tolerance || fabs(step - fabs(r)) <= tolerance;
}A scale-aware starting point for finite values and a positive, nonzero step.
What this helper does—and does not promise
isfiniterejects NaN and infinity, whilestep <= 0.0establishes the helper’s positive-step contract.DBL_EPSILONdescribes the spacing near1.0; scaling it makes the initial tolerance respond to operand magnitude.The second comparison handles a remainder that lands just below
stepbecause of rounding near a multiple.The factor
8.0is an engineering choice, not a language rule. Replace it with a tolerance justified by measurement precision and accumulated computation error.
A quick diagnostic checklist
`float` and `double`: use
fmodforfmod; do not change only the destination type.Unexpected `double` operand: inspect decimal literals—
3.0isdouble, whereas3.0fisfloat.Undefined reference to `fmod`: add
-lmafter the object files on platforms that require explicit math-library linkage.Wrong printed value: use
%f,%g, or another floating conversion for a floating result;%dexpects anint.No fractional values should exist: redesign the variables as integer types instead of repeatedly casting them at the operator.
Comparing with zero: decide whether exact binary equality is truly intended or whether the domain needs a documented tolerance.
Continue with the right remainder topic
For a deeper comparison of fmod, fmodf, fmodl, and remainder, continue with floating-point remainder in C. If your operands are integers and the real goal is an exact divisibility test, use the C modulo and divisibility example.
Technical references
GNU C Library remainder functions documents
fmod,fmodf, andfmodlbehavior.GCC diagnostic formatting explains how operand locations and types appear in binary-operator errors.
Comments and corrections