Files
beyond-interviews/analysis/#02 — Floating Point Equality Is a Lie/readmy.md

262 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Analysis #02 — Floating Point Equality Is a Lie
## Problem
At interviews, you often see something like:
> Compare two floating point numbers and determine if they are equal.
Typical answer:
```cpp
if (a == b) { }
```
Or the “better” version:
```cpp
fabs(a - b) < 1e-9
```
Looks correct. In real engineering — not enough.
---
## The Real Issue
The problem is not that `==` is bad.
The problem is the assumption:
> There exists one correct way to compare floating point numbers.
There isnt.
---
## Why `==` Fails
Classic example:
```cpp
double a = 0.1 + 0.2;
double b = 0.3;
```
`a != b`
Reasons:
- binary representation
- rounding errors
- accumulation of operations
---
## Why “Just Use Epsilon” Is Not Enough
### Scale problem
```cpp
a = 1e9;
b = a + 0.1;
```
`1e-9` is meaningless here.
---
### Near-zero problem
```cpp
a = 1e-12;
b = 2e-12;
```
`1e-9` is too large.
---
### Meaning problem
What are these values?
- sensor readings?
- computed values?
- scaled integers?
- geometry?
Without context, comparison is undefined.
---
## What This Actually Tests
In interviews, this checks:
- awareness of IEEE754
- prior exposure to the trap
- memorized epsilon usage
Not real engineering thinking.
---
## Real-World Behavior
### Sensor example
```cpp
if (temperature == target)
```
System never stabilizes.
Reality:
- noise
- quantization
- jitter
Solution:
- tolerance
- hysteresis
- filtering
---
### Computation paths
```cpp
double x = (a + b) + c;
double y = a + (b + c);
```
Different results.
---
### Scaled data (CAN-like)
```cpp
raw = 1234;
value = raw * 0.1;
expected = 123.4;
```
Comparison fails.
---
## Demo Code
A full demonstration program is available:
- examples/main.cpp
It shows:
- where `==` fails
- where fixed epsilon fails
- why scale matters
- how noise breaks naive logic
- why hysteresis is often required
---
## Example Output (fill with your own results)
Below you can include actual output from your system.
```text
[insert your real output here]
```
Use this section to demonstrate:
- how behavior changes with different eps values
- how noise affects stability
- differences between float and double
- how hysteresis stabilizes the system
---
## Better Approaches
### Absolute
```cpp
fabs(a - b) < abs_eps
```
---
### Relative
```cpp
fabs(a - b) < rel_eps * max(fabs(a), fabs(b))
```
---
### Combined
```cpp
fabs(a - b) <= max(abs_eps, rel_eps * max(fabs(a), fabs(b)))
```
---
### Or Avoid Float
Compare:
- raw values
- fixed-point
- integers
---
### Or Change the Question
Instead of:
> Are values equal?
Ask:
> Are they close enough for the system?
---
## Common Mistakes
- Using `==`
- Fixed epsilon everywhere
- Only relative error
- Only absolute error
- Blind rounding
---
## Key Takeaway
Floating point comparison is not a trick.
It is a modeling problem.
---
## Project Perspective
Does this problem exist in real engineering?
Yes.
In interview form?
Almost never.
Because real systems have:
- noise
- scale
- constraints
- consequences
And no universal epsilon.