C#
floating point comparison
programming
coding
software development

Floating point comparison functions for C

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Floating-point comparison in C is harder than it first looks because many decimal values cannot be represented exactly in binary. If two numbers arrive through different calculations, == can fail even when the math says they should match.

Why Direct Equality Often Fails

Binary floating-point formats store approximations. A classic example is 0.1 + 0.2, which is very close to 0.3 but not bit-for-bit identical on most systems.

c
1#include <stdio.h>
2
3int main(void) {
4    double a = 0.1 + 0.2;
5    double b = 0.3;
6
7    printf("a = %.17f\n", a);
8    printf("b = %.17f\n", b);
9    printf("a == b ? %s\n", (a == b) ? "true" : "false");
10    return 0;
11}

That does not mean floating point is broken. It means you need a comparison rule that matches the problem you are solving. Exact equality is still valid for some cases, such as checking whether a value is exactly 0.0 because it was assigned directly, or comparing sentinel values that must be identical by design.

A Practical Comparison Function

The most useful approach is usually a combined absolute and relative tolerance. Absolute tolerance handles values near zero. Relative tolerance handles larger magnitudes where a small percentage error is acceptable.

c
1#include <float.h>
2#include <math.h>
3#include <stdbool.h>
4#include <stdio.h>
5
6bool almost_equal(double a, double b, double abs_tol, double rel_tol) {
7    double diff = fabs(a - b);
8    if (diff <= abs_tol) {
9        return true;
10    }
11
12    double largest = fmax(fabs(a), fabs(b));
13    return diff <= largest * rel_tol;
14}
15
16int main(void) {
17    double x = 1000000.0;
18    double y = 1000000.0001;
19
20    if (almost_equal(x, y, 1e-9, 1e-9)) {
21        printf("close enough\n");
22    } else {
23        printf("different\n");
24    }
25    return 0;
26}

This pattern is more robust than using DBL_EPSILON by itself. DBL_EPSILON describes machine precision near 1.0. It is not a universal tolerance for every scale of input.

Choosing a Tolerance

Tolerance values are application-specific. Financial calculations, geometry, physics simulation, and user-interface layout all have different error budgets. A reasonable comparison function is only half of the solution; the other half is choosing thresholds that reflect the domain.

As a rule:

  • use absolute tolerance when comparing against zero or very small values
  • use relative tolerance when values can become large
  • avoid copying a random epsilon from the internet without understanding the units

For example, if values are expected to be around 1e6, an absolute tolerance of 1e-12 is usually meaningless. If values are expected to be near zero, relying on relative tolerance alone can also fail because the scale collapses.

Special Values: NaN and Infinity

Comparison helpers should also account for special floating-point values. NaN is never equal to anything, including itself. Positive and negative infinity are exact symbolic values and can be compared directly when that behavior is what you want.

c
1#include <math.h>
2#include <stdbool.h>
3
4bool safe_equal(double a, double b, double abs_tol, double rel_tol) {
5    if (isnan(a) || isnan(b)) {
6        return false;
7    }
8    if (isinf(a) || isinf(b)) {
9        return a == b;
10    }
11    return almost_equal(a, b, abs_tol, rel_tol);
12}

That policy is simple and predictable. If your program needs a different rule, such as treating two NaN values as equivalent missing data, make that behavior explicit instead of hiding it inside a generic helper.

When Exact Equality Is Still Correct

Developers sometimes hear "never use == with floating point" and overcorrect. Exact equality is still appropriate when you are checking values that should be identical by construction. Examples include values copied without arithmetic, results read from the same serialized source, or state-machine markers using specific constants.

The real mistake is using == after a chain of computations that introduces rounding. In those cases, compare meaning, not raw bits.

Common Pitfalls

  • Using DBL_EPSILON as a one-size-fits-all tolerance for every magnitude.
  • Comparing only with relative tolerance and then failing near zero.
  • Comparing only with absolute tolerance and then misclassifying large values.
  • Forgetting to define a policy for NaN and infinity.
  • Assuming floating-point comparison rules from one application domain fit another.

Summary

  • Direct == comparison is often wrong after real floating-point arithmetic.
  • A combined absolute-and-relative tolerance is the most practical general solution.
  • 'DBL_EPSILON is a machine constant, not a universal business rule.'
  • Near-zero comparisons need absolute tolerance.
  • 'NaN and infinity should be handled explicitly so comparison behavior stays predictable.'

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.