Compare commits
16 Commits
006ac887ea
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 269d560847 | |||
| 9ad604196e | |||
| b14ef0beca | |||
| f279ec4ff3 | |||
| d1d2109d13 | |||
| 4fdcf67b0a | |||
| 8408537b81 | |||
| 140145c257 | |||
| d6084d6aea | |||
| 52114dae41 | |||
| 244dc0afa6 | |||
| 91a2f7b159 | |||
| bc6a0f942e | |||
| 0cbdf699f1 | |||
| 3a5ca9d5b1 | |||
| 831f7f0215 |
135
README.md
135
README.md
@@ -1,135 +0,0 @@
|
|||||||
# Beyond Interviews
|
|
||||||
## Real Engineering Problems
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What is this?
|
|
||||||
|
|
||||||
This project is about one simple question:
|
|
||||||
|
|
||||||
> Do typical coding interview problems reflect real engineering work?
|
|
||||||
|
|
||||||
Short answer: not really.
|
|
||||||
|
|
||||||
But instead of complaining about it, this project tries to **understand why**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why this exists
|
|
||||||
|
|
||||||
Many interview processes rely on:
|
|
||||||
|
|
||||||
- LeetCode
|
|
||||||
- Codility
|
|
||||||
- algorithmic puzzles
|
|
||||||
|
|
||||||
These tasks are:
|
|
||||||
|
|
||||||
- abstract
|
|
||||||
- isolated
|
|
||||||
- time-pressured
|
|
||||||
|
|
||||||
Real engineering is not.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What this project does
|
|
||||||
|
|
||||||
For each interview problem, we:
|
|
||||||
|
|
||||||
1. Look at the original task
|
|
||||||
2. Show the typical “interview solution”
|
|
||||||
3. Explain what it actually tests
|
|
||||||
4. Compare it with real-world engineering
|
|
||||||
5. Find (if possible) a real equivalent
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Core idea
|
|
||||||
|
|
||||||
There is a gap:
|
|
||||||
|
|
||||||
```
|
|
||||||
Interview problems ≠ Real engineering work
|
|
||||||
```
|
|
||||||
|
|
||||||
This project explores that gap.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Not a rant
|
|
||||||
|
|
||||||
This is **not** about:
|
|
||||||
|
|
||||||
- complaining
|
|
||||||
- mocking interviews
|
|
||||||
- saying "everything is useless"
|
|
||||||
|
|
||||||
Instead:
|
|
||||||
|
|
||||||
- understand what these problems measure
|
|
||||||
- show where they help
|
|
||||||
- show where they don’t
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Engineering focus
|
|
||||||
|
|
||||||
Special attention is given to **systems and embedded development**, where reality looks very different:
|
|
||||||
|
|
||||||
- imperfect data
|
|
||||||
- hardware constraints
|
|
||||||
- memory limits
|
|
||||||
- timing issues
|
|
||||||
- debugging real systems
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Repository structure
|
|
||||||
|
|
||||||
```
|
|
||||||
analysis/
|
|
||||||
01-.../
|
|
||||||
02-.../
|
|
||||||
```
|
|
||||||
|
|
||||||
Each analysis contains:
|
|
||||||
|
|
||||||
- explanation
|
|
||||||
- comparison
|
|
||||||
- conclusions
|
|
||||||
- sometimes code
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How to read this
|
|
||||||
|
|
||||||
Start with any analysis.
|
|
||||||
|
|
||||||
Each one answers:
|
|
||||||
|
|
||||||
> Would this problem appear in real engineering?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why it matters
|
|
||||||
|
|
||||||
Because solving puzzles ≠ building systems.
|
|
||||||
|
|
||||||
And understanding the difference makes you a better engineer.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Work in progress.
|
|
||||||
|
|
||||||
Problems are added when ready — no fixed schedule.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Author note
|
|
||||||
|
|
||||||
This project started as a personal attempt to make interview preparation meaningful.
|
|
||||||
|
|
||||||
If it helps someone else — even better.
|
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
# 00 — Why LeetCode Problems Don't Reflect Real Engineering
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This analysis explores why common interview problems (LeetCode, Codility, etc.) often do not reflect real engineering work.
|
||||||
|
|
||||||
|
The goal is not to criticize these platforms, but to understand what they actually measure and how that differs from real-world engineering.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
Engineers can spend months preparing for algorithmic interviews:
|
||||||
|
|
||||||
|
- solving hundreds of problems
|
||||||
|
- memorizing patterns
|
||||||
|
- practicing speed
|
||||||
|
|
||||||
|
And still struggle with real-world tasks such as:
|
||||||
|
|
||||||
|
- debugging complex systems
|
||||||
|
- working with imperfect data
|
||||||
|
- handling system constraints
|
||||||
|
|
||||||
|
This creates a gap:
|
||||||
|
|
||||||
|
Preparation for interviews ≠ Readiness for engineering work
|
||||||
|
Readiness for engineering work ≠ Readiness for interviews
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nature of LeetCode Problems
|
||||||
|
|
||||||
|
Typical characteristics:
|
||||||
|
|
||||||
|
- well-defined inputs
|
||||||
|
- deterministic behavior
|
||||||
|
- no external systems
|
||||||
|
- no side effects
|
||||||
|
- one optimal solution
|
||||||
|
|
||||||
|
These are closer to:
|
||||||
|
|
||||||
|
> mathematical puzzles or competitive programming
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Similarity to Academic Exams
|
||||||
|
|
||||||
|
These problems resemble university exams:
|
||||||
|
|
||||||
|
- limited types of problems
|
||||||
|
- expected “correct” solutions
|
||||||
|
- repetition-based preparation
|
||||||
|
|
||||||
|
Students can train for years.
|
||||||
|
|
||||||
|
However:
|
||||||
|
|
||||||
|
> after 5–10 years in industry, this knowledge naturally fades
|
||||||
|
|
||||||
|
Why?
|
||||||
|
|
||||||
|
- algorithms are already implemented
|
||||||
|
- they are tested and optimized
|
||||||
|
- they are accessed through libraries
|
||||||
|
|
||||||
|
Engineers need to know:
|
||||||
|
|
||||||
|
- what to use
|
||||||
|
not
|
||||||
|
- how to reimplement everything from scratch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What These Problems Actually Test
|
||||||
|
|
||||||
|
They effectively measure:
|
||||||
|
|
||||||
|
- knowledge of algorithms and data structures
|
||||||
|
- pattern recognition
|
||||||
|
- speed under pressure
|
||||||
|
|
||||||
|
But they do not measure:
|
||||||
|
|
||||||
|
- system design
|
||||||
|
- debugging skills
|
||||||
|
- working with constraints
|
||||||
|
- maintaining large systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Is Missing
|
||||||
|
|
||||||
|
Real engineering involves:
|
||||||
|
|
||||||
|
- incomplete or unclear requirements
|
||||||
|
- unreliable data
|
||||||
|
- system integration issues
|
||||||
|
- hardware and performance constraints
|
||||||
|
- long-term maintainability
|
||||||
|
|
||||||
|
These aspects are almost entirely absent in interview problems.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Impact on Experienced Engineers
|
||||||
|
|
||||||
|
A critical and often overlooked effect:
|
||||||
|
|
||||||
|
Algorithmic interviews may filter out experienced engineers.
|
||||||
|
|
||||||
|
### 1. Shift Toward Academic Knowledge
|
||||||
|
|
||||||
|
Experienced engineers:
|
||||||
|
|
||||||
|
- do not memorize dozens of algorithms
|
||||||
|
- do not implement them from scratch
|
||||||
|
- do not optimize in isolation
|
||||||
|
|
||||||
|
They:
|
||||||
|
|
||||||
|
- use proven libraries
|
||||||
|
- select appropriate solutions
|
||||||
|
- think in systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Knowledge ≠ Usage
|
||||||
|
|
||||||
|
Even if they know algorithms:
|
||||||
|
|
||||||
|
- they may not have implemented them recently
|
||||||
|
- they are not trained for timed coding
|
||||||
|
- they are not optimized for pattern recall
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
> a 10–20 year engineer may appear weaker than a trained candidate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Abstraction in Real Work
|
||||||
|
|
||||||
|
In industry:
|
||||||
|
|
||||||
|
- sorting is already implemented
|
||||||
|
- data structures are provided
|
||||||
|
- algorithms are tested
|
||||||
|
|
||||||
|
Engineers focus on:
|
||||||
|
|
||||||
|
- architecture
|
||||||
|
- data flow
|
||||||
|
- system reliability
|
||||||
|
|
||||||
|
Interviews shift them back to:
|
||||||
|
|
||||||
|
> “implement everything manually in 30 minutes”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Selection Paradox
|
||||||
|
|
||||||
|
This creates a paradox:
|
||||||
|
|
||||||
|
- experienced engineers get filtered out
|
||||||
|
- trained candidates pass
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
> hiring selects problem solvers, not engineers
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why This Is a Problem
|
||||||
|
|
||||||
|
Using only such problems:
|
||||||
|
|
||||||
|
- removes strong candidates
|
||||||
|
- biases toward trained individuals
|
||||||
|
- reduces hiring effectiveness
|
||||||
|
|
||||||
|
The issue is not the problems themselves, but how they are used.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proper Perspective
|
||||||
|
|
||||||
|
LeetCode is useful as:
|
||||||
|
|
||||||
|
- mental training
|
||||||
|
- practice
|
||||||
|
- competition
|
||||||
|
|
||||||
|
But not as:
|
||||||
|
|
||||||
|
> a primary indicator of engineering ability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Question
|
||||||
|
|
||||||
|
Would solving LeetCode problems make you a better engineer?
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
||||||
|
- partially — improves thinking
|
||||||
|
- insufficient — for real systems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Takeaway
|
||||||
|
|
||||||
|
LeetCode is not bad.
|
||||||
|
|
||||||
|
Mistaking it for engineering is.
|
||||||
@@ -195,15 +195,13 @@ Wait for valid data.
|
|||||||
```cpp
|
```cpp
|
||||||
auto result = safe_add(a, b);
|
auto result = safe_add(a, b);
|
||||||
|
|
||||||
if (result.invalid)
|
if (result.invalid) {
|
||||||
{
|
|
||||||
publish_invalid();
|
publish_invalid();
|
||||||
error_counter++;
|
error_counter++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.value > c)
|
if (result.value > c) {
|
||||||
{
|
|
||||||
update_state();
|
update_state();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Compiler
|
||||||
|
CXX := g++
|
||||||
|
|
||||||
|
# Common settings
|
||||||
|
STD := -std=c++14
|
||||||
|
TARGET := floating_demo
|
||||||
|
SRC := main.cpp
|
||||||
|
|
||||||
|
# Debug flags
|
||||||
|
CXXFLAGS_DEBUG := $(STD) -O0 -Wall -Wextra -pedantic
|
||||||
|
|
||||||
|
# Release flags
|
||||||
|
CXXFLAGS_RELEASE := $(STD) -O2
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: debug
|
||||||
|
|
||||||
|
# Debug build
|
||||||
|
debug:
|
||||||
|
$(CXX) $(CXXFLAGS_DEBUG) $(SRC) -o $(TARGET)
|
||||||
|
|
||||||
|
# Release build
|
||||||
|
release:
|
||||||
|
$(CXX) $(CXXFLAGS_RELEASE) $(SRC) -o $(TARGET)
|
||||||
|
|
||||||
|
# Clean
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
||||||
|
|
||||||
|
# Phony targets
|
||||||
|
.PHONY: all debug release clean
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
90,101c90,101
|
||||||
|
< 0 24.97779766 false true true
|
||||||
|
< 1 25.01916948 false true true
|
||||||
|
< 2 25.02972687 false true true
|
||||||
|
< 3 25.01870257 false true true
|
||||||
|
< 4 24.96365349 false true true
|
||||||
|
< 5 25.02417787 false true true
|
||||||
|
< 6 25.01521257 false true true
|
||||||
|
< 7 25.01746188 false true true
|
||||||
|
< 8 25.01469876 false true true
|
||||||
|
< 9 24.95849519 false true true
|
||||||
|
< 10 25.00975313 false true true
|
||||||
|
< 11 24.96665774 false true true
|
||||||
|
---
|
||||||
|
> 0 24.97471804 false true true
|
||||||
|
> 1 25.0413491 false true true
|
||||||
|
> 2 24.99852989 false true true
|
||||||
|
> 3 24.99317494 false true true
|
||||||
|
> 4 25.00292729 false true true
|
||||||
|
> 5 25.03122934 false true true
|
||||||
|
> 6 24.97063462 false true true
|
||||||
|
> 7 24.9619692 false true true
|
||||||
|
> 8 24.99279928 false true true
|
||||||
|
> 9 24.97964776 false true true
|
||||||
|
> 10 25.04053616 false true true
|
||||||
|
> 11 25.0353959 false true true
|
||||||
|
105,116c105,116
|
||||||
|
< 0 24.99675513 false true true
|
||||||
|
< 1 24.9971971 false true true
|
||||||
|
< 2 25.00143947 false true true
|
||||||
|
< 3 24.99902736 false true true
|
||||||
|
< 4 24.99946988 false true true
|
||||||
|
< 5 24.99607726 false true true
|
||||||
|
< 6 24.99667581 false true true
|
||||||
|
< 7 25.00177208 false true true
|
||||||
|
< 8 24.99822762 false true true
|
||||||
|
< 9 25.00066511 false true true
|
||||||
|
< 10 24.997119 false true true
|
||||||
|
< 11 25.0030632 false true true
|
||||||
|
---
|
||||||
|
> 0 25.00020134 false true true
|
||||||
|
> 1 25.00382071 false true true
|
||||||
|
> 2 25.00383611 false true true
|
||||||
|
> 3 24.99614752 false true true
|
||||||
|
> 4 25.00265027 false true true
|
||||||
|
> 5 25.00074494 false true true
|
||||||
|
> 6 24.99856782 false true true
|
||||||
|
> 7 25.00364029 false true true
|
||||||
|
> 8 25.00150722 false true true
|
||||||
|
> 9 25.00310794 false true true
|
||||||
|
> 10 25.00211411 false true true
|
||||||
|
> 11 25.00197054 false true true
|
||||||
|
120,131c120,131
|
||||||
|
< 0 24.99998171 false true true
|
||||||
|
< 1 25.00043692 false false false
|
||||||
|
< 2 24.99991995 false true true
|
||||||
|
< 3 24.99953881 false false false
|
||||||
|
< 4 24.99997226 false true true
|
||||||
|
< 5 25.00001312 false true true
|
||||||
|
< 6 24.99969943 false false false
|
||||||
|
< 7 25.00025024 false false false
|
||||||
|
< 8 24.99970481 false false false
|
||||||
|
< 9 25.0004967 false false false
|
||||||
|
< 10 24.99993727 false true true
|
||||||
|
< 11 24.99984134 false false false
|
||||||
|
---
|
||||||
|
> 0 25.00034068 false false false
|
||||||
|
> 1 24.99978583 false false false
|
||||||
|
> 2 24.99965013 false false false
|
||||||
|
> 3 25.00030996 false false false
|
||||||
|
> 4 25.00044598 false false false
|
||||||
|
> 5 25.00007675 false true true
|
||||||
|
> 6 25.00043085 false false false
|
||||||
|
> 7 24.99969316 false false false
|
||||||
|
> 8 24.99999024 false true true
|
||||||
|
> 9 24.99991615 false true true
|
||||||
|
> 10 25.00012491 false false false
|
||||||
|
> 11 24.99951951 false false false
|
||||||
356
analysis/02-Floating_Point_Equality_Is_a_Lie/example/main.cpp
Normal file
356
analysis/02-Floating_Point_Equality_Is_a_Lie/example/main.cpp
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool equal_naive (T a, T b) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool equal_abs (T a, T b, T eps) {
|
||||||
|
return std::fabs (a - b) <= eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool equal_rel (T a, T b, T eps) {
|
||||||
|
const T scale = std::max (std::fabs (a), std::fabs (b));
|
||||||
|
return std::fabs (a - b) <= eps * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool equal_combined (T a, T b, T abs_eps, T rel_eps) {
|
||||||
|
const T scale = std::max (std::fabs (a), std::fabs (b));
|
||||||
|
return std::fabs (a - b) <= std::max (abs_eps, rel_eps * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void print_bool_result (const std::string &label, bool value) {
|
||||||
|
std::cout << " " << std::left << std::setw (28) << label
|
||||||
|
<< ": " << (value ? "true" : "false") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void print_value_line (const std::string &label, T value) {
|
||||||
|
std::cout << " " << std::left << std::setw (28) << label
|
||||||
|
<< ": " << std::setprecision (std::numeric_limits<T>::digits10 + 2)
|
||||||
|
<< value << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_section (const std::string &title) {
|
||||||
|
std::cout << "\n============================================================\n";
|
||||||
|
std::cout << title << "\n";
|
||||||
|
std::cout << "============================================================\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_basic_01_plus_02() {
|
||||||
|
print_section ("1. Basic classic: 0.1 + 0.2 != 0.3");
|
||||||
|
|
||||||
|
const double a = 0.1 + 0.2;
|
||||||
|
const double b = 0.3;
|
||||||
|
|
||||||
|
print_value_line ("a", a);
|
||||||
|
print_value_line ("b", b);
|
||||||
|
print_value_line ("abs(a - b)", std::fabs (a - b));
|
||||||
|
|
||||||
|
print_bool_result<double> ("a == b", equal_naive (a, b));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-12", equal_abs (a, b, 1e-12));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-9", equal_abs (a, b, 1e-9));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (a, b, 1e-12, 1e-12));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_large_numbers() {
|
||||||
|
print_section ("2. Large numbers: fixed absolute epsilon becomes useless");
|
||||||
|
|
||||||
|
const double a = 1e9;
|
||||||
|
const double b = a + 0.1;
|
||||||
|
|
||||||
|
print_value_line ("a", a);
|
||||||
|
print_value_line ("b", b);
|
||||||
|
print_value_line ("abs(a - b)", std::fabs (a - b));
|
||||||
|
|
||||||
|
print_bool_result<double> ("a == b", equal_naive (a, b));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-12", equal_abs (a, b, 1e-12));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-9", equal_abs (a, b, 1e-9));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-3", equal_abs (a, b, 1e-3));
|
||||||
|
|
||||||
|
print_bool_result<double> ("rel eps = 1e-12", equal_rel (a, b, 1e-12));
|
||||||
|
print_bool_result<double> ("rel eps = 1e-9", equal_rel (a, b, 1e-9));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (a, b, 1e-9, 1e-9));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_small_numbers() {
|
||||||
|
print_section ("3. Very small numbers: fixed absolute epsilon can be too large");
|
||||||
|
|
||||||
|
const double a = 1e-12;
|
||||||
|
const double b = 2e-12;
|
||||||
|
|
||||||
|
print_value_line ("a", a);
|
||||||
|
print_value_line ("b", b);
|
||||||
|
print_value_line ("abs(a - b)", std::fabs (a - b));
|
||||||
|
|
||||||
|
print_bool_result<double> ("a == b", equal_naive (a, b));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-9", equal_abs (a, b, 1e-9));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-12", equal_abs (a, b, 1e-12));
|
||||||
|
print_bool_result<double> ("rel eps = 1e-9", equal_rel (a, b, 1e-9));
|
||||||
|
print_bool_result<double> ("rel eps = 0.5", equal_rel (a, b, 0.5));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (a, b, 1e-15, 1e-6));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_near_zero_relative_problem() {
|
||||||
|
print_section ("4. Near zero: relative comparison alone is weak");
|
||||||
|
|
||||||
|
const double a = 0.0;
|
||||||
|
const double b = 1e-15;
|
||||||
|
|
||||||
|
print_value_line ("a", a);
|
||||||
|
print_value_line ("b", b);
|
||||||
|
print_value_line ("abs(a - b)", std::fabs (a - b));
|
||||||
|
|
||||||
|
print_bool_result<double> ("a == b", equal_naive (a, b));
|
||||||
|
print_bool_result<double> ("rel eps = 1e-6", equal_rel (a, b, 1e-6));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-12", equal_abs (a, b, 1e-12));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (a, b, 1e-12, 1e-6));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_associativity() {
|
||||||
|
print_section ("5. Same math on paper, different result in floating point");
|
||||||
|
|
||||||
|
const double a = 1e16;
|
||||||
|
const double b = -1e16;
|
||||||
|
const double c = 1.0;
|
||||||
|
|
||||||
|
const double x = (a + b) + c;
|
||||||
|
const double y = a + (b + c);
|
||||||
|
|
||||||
|
print_value_line ("x = (a + b) + c", x);
|
||||||
|
print_value_line ("y = a + (b + c)", y);
|
||||||
|
print_value_line ("abs(x - y)", std::fabs (x - y));
|
||||||
|
|
||||||
|
print_bool_result<double> ("x == y", equal_naive (x, y));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (x, y, 1e-12, 1e-12));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_accumulation() {
|
||||||
|
print_section ("6. Accumulation of error: repeated addition");
|
||||||
|
|
||||||
|
double x = 0.0;
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
x += 0.1;
|
||||||
|
|
||||||
|
const double y = 100000.0;
|
||||||
|
|
||||||
|
print_value_line ("x", x);
|
||||||
|
print_value_line ("y", y);
|
||||||
|
print_value_line ("abs(x - y)", std::fabs (x - y));
|
||||||
|
|
||||||
|
print_bool_result<double> ("x == y", equal_naive (x, y));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-9", equal_abs (x, y, 1e-9));
|
||||||
|
print_bool_result<double> ("abs eps = 1e-6", equal_abs (x, y, 1e-6));
|
||||||
|
print_bool_result<double> ("combined", equal_combined (x, y, 1e-6, 1e-12));
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_float_vs_double() {
|
||||||
|
print_section ("7. float vs double: same idea, different precision");
|
||||||
|
|
||||||
|
float af = 0.1f + 0.2f;
|
||||||
|
float bf = 0.3f;
|
||||||
|
|
||||||
|
double ad = 0.1 + 0.2;
|
||||||
|
double bd = 0.3;
|
||||||
|
|
||||||
|
print_value_line ("float a", af);
|
||||||
|
print_value_line ("float b", bf);
|
||||||
|
print_value_line ("float abs diff", std::fabs (af - bf));
|
||||||
|
print_bool_result<float> ("float a == b", equal_naive (af, bf));
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
print_value_line ("double a", ad);
|
||||||
|
print_value_line ("double b", bd);
|
||||||
|
print_value_line ("double abs diff", std::fabs (ad - bd));
|
||||||
|
print_bool_result<double> ("double a == b", equal_naive (ad, bd));
|
||||||
|
}
|
||||||
|
|
||||||
|
double random_noise (double amplitude) {
|
||||||
|
const double unit = static_cast<double> (std::rand()) / static_cast<double> (RAND_MAX);
|
||||||
|
return (unit * 2.0 - 1.0) * amplitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_sensor_simulation (double noise_amplitude, double abs_eps) {
|
||||||
|
const double target = 25.0;
|
||||||
|
const double rel_eps = 1e-6;
|
||||||
|
|
||||||
|
std::cout << "\nNoise amplitude: +/-" << noise_amplitude
|
||||||
|
<< ", abs_eps: " << abs_eps << "\n";
|
||||||
|
|
||||||
|
std::cout << " " << std::left
|
||||||
|
<< std::setw (10) << "sample"
|
||||||
|
<< std::setw (18) << "value"
|
||||||
|
<< std::setw (10) << "=="
|
||||||
|
<< std::setw (10) << "abs"
|
||||||
|
<< std::setw (10) << "comb"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
const double value = target + random_noise (noise_amplitude);
|
||||||
|
|
||||||
|
const bool naive = equal_naive (value, target);
|
||||||
|
const bool abs_ok = equal_abs (value, target, abs_eps);
|
||||||
|
const bool comb_ok = equal_combined (value, target, abs_eps, rel_eps);
|
||||||
|
|
||||||
|
std::cout << " " << std::left
|
||||||
|
<< std::setw (10) << i
|
||||||
|
<< std::setw (18) << std::setprecision (10) << value
|
||||||
|
<< std::setw (10) << (naive ? "true" : "false")
|
||||||
|
<< std::setw (10) << (abs_ok ? "true" : "false")
|
||||||
|
<< std::setw (10) << (comb_ok ? "true" : "false")
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_sensor_noise() {
|
||||||
|
print_section ("8. Sensor-like values: 'equal' is often the wrong question");
|
||||||
|
|
||||||
|
run_sensor_simulation (0.05, 0.1);
|
||||||
|
run_sensor_simulation (0.005, 0.01);
|
||||||
|
run_sensor_simulation (0.0005, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_scaled_integer_vs_double() {
|
||||||
|
print_section ("9. Scaled integer values: often better to compare raw domain");
|
||||||
|
|
||||||
|
const int raw_value = 1234; // imagine 123.4 in deci-units
|
||||||
|
const int raw_target = 1234;
|
||||||
|
|
||||||
|
const double scaled_value = raw_value * 0.1;
|
||||||
|
const double scaled_target = 123.4;
|
||||||
|
|
||||||
|
print_value_line ("raw_value", raw_value);
|
||||||
|
print_value_line ("raw_target", raw_target);
|
||||||
|
print_bool_result<int> ("raw_value == raw_target", raw_value == raw_target);
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
print_value_line ("scaled_value", scaled_value);
|
||||||
|
print_value_line ("scaled_target", scaled_target);
|
||||||
|
print_value_line ("abs diff", std::fabs (scaled_value - scaled_target));
|
||||||
|
print_bool_result<double> ("scaled_value == scaled_target",
|
||||||
|
equal_naive (scaled_value, scaled_target));
|
||||||
|
print_bool_result<double> ("combined",
|
||||||
|
equal_combined (scaled_value, scaled_target, 1e-12, 1e-12));
|
||||||
|
|
||||||
|
std::cout << "\n Note: if your system is naturally discrete, comparing raw units can be simpler\n";
|
||||||
|
std::cout << " and more honest than converting everything to floating point too early.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_rounding_is_not_magic() {
|
||||||
|
print_section ("10. Rounding is not a universal fix");
|
||||||
|
|
||||||
|
const double a = 1.0049;
|
||||||
|
const double b = 1.0051;
|
||||||
|
|
||||||
|
const double rounded_a_2 = std::round (a * 100.0) / 100.0;
|
||||||
|
const double rounded_b_2 = std::round (b * 100.0) / 100.0;
|
||||||
|
|
||||||
|
const double rounded_a_3 = std::round (a * 1000.0) / 1000.0;
|
||||||
|
const double rounded_b_3 = std::round (b * 1000.0) / 1000.0;
|
||||||
|
|
||||||
|
print_value_line ("a", a);
|
||||||
|
print_value_line ("b", b);
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
print_value_line ("round(a, 2)", rounded_a_2);
|
||||||
|
print_value_line ("round(b, 2)", rounded_b_2);
|
||||||
|
print_bool_result<double> ("equal after round(2)", rounded_a_2 == rounded_b_2);
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
print_value_line ("round(a, 3)", rounded_a_3);
|
||||||
|
print_value_line ("round(b, 3)", rounded_b_3);
|
||||||
|
print_bool_result<double> ("equal after round(3)", rounded_a_3 == rounded_b_3);
|
||||||
|
|
||||||
|
std::cout << "\n Rounding may hide differences or invent equality depending on chosen precision.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void example_hysteresis() {
|
||||||
|
print_section ("11. Hysteresis: in real systems you often want state logic, not equality");
|
||||||
|
|
||||||
|
const double target = 25.0;
|
||||||
|
const double on_threshold = target - 0.1;
|
||||||
|
const double off_threshold = target + 0.1;
|
||||||
|
|
||||||
|
const double signal[] = {
|
||||||
|
24.92, 24.97, 25.01, 25.05, 24.99, 25.08, 25.11, 25.06,
|
||||||
|
24.98, 24.91, 24.89, 24.95, 25.02, 25.12, 25.07, 24.93
|
||||||
|
};
|
||||||
|
|
||||||
|
bool heater_simple = true;
|
||||||
|
bool heater_hysteresis = true;
|
||||||
|
|
||||||
|
std::cout << " " << std::left
|
||||||
|
<< std::setw (8) << "step"
|
||||||
|
<< std::setw (12) << "value"
|
||||||
|
<< std::setw (16) << "simple_ctrl"
|
||||||
|
<< std::setw (16) << "hyst_ctrl"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (sizeof (signal) / sizeof (signal[0])); ++i) {
|
||||||
|
const double value = signal[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple control:
|
||||||
|
* heater ON below target
|
||||||
|
* heater OFF at or above target
|
||||||
|
* This tends to chatter near the threshold.
|
||||||
|
*/
|
||||||
|
heater_simple = value < target;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hysteresis control:
|
||||||
|
* heater turns ON only below lower threshold
|
||||||
|
* heater turns OFF only above upper threshold
|
||||||
|
* This reduces chatter around the target.
|
||||||
|
*/
|
||||||
|
if (heater_hysteresis && value > off_threshold)
|
||||||
|
heater_hysteresis = false;
|
||||||
|
else if (!heater_hysteresis && value < on_threshold)
|
||||||
|
heater_hysteresis = true;
|
||||||
|
|
||||||
|
std::cout << " " << std::left
|
||||||
|
<< std::setw (8) << i
|
||||||
|
<< std::setw (12) << std::setprecision (6) << value
|
||||||
|
<< std::setw (16) << (heater_simple ? "HEATER ON" : "HEATER OFF")
|
||||||
|
<< std::setw (16) << (heater_hysteresis ? "HEATER ON" : "HEATER OFF")
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n This is the key engineering point:\n";
|
||||||
|
std::cout << " sometimes the answer is not a better equality test,\n";
|
||||||
|
std::cout << " but a better control model.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::srand (static_cast<unsigned int> (std::time (NULL)));
|
||||||
|
|
||||||
|
std::cout << std::boolalpha;
|
||||||
|
|
||||||
|
example_basic_01_plus_02();
|
||||||
|
example_large_numbers();
|
||||||
|
example_small_numbers();
|
||||||
|
example_near_zero_relative_problem();
|
||||||
|
example_associativity();
|
||||||
|
example_accumulation();
|
||||||
|
example_float_vs_double();
|
||||||
|
example_sensor_noise();
|
||||||
|
example_scaled_integer_vs_double();
|
||||||
|
example_rounding_is_not_magic();
|
||||||
|
example_hysteresis();
|
||||||
|
|
||||||
|
std::cout << "\nDone.\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
|
||||||
|
============================================================
|
||||||
|
1. Basic classic: 0.1 + 0.2 != 0.3
|
||||||
|
============================================================
|
||||||
|
a : 0.30000000000000004
|
||||||
|
b : 0.29999999999999999
|
||||||
|
abs(a - b) : 5.5511151231257827e-17
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
abs eps = 1e-9 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
2. Large numbers: fixed absolute epsilon becomes useless
|
||||||
|
============================================================
|
||||||
|
a : 1000000000
|
||||||
|
b : 1000000000.1
|
||||||
|
abs(a - b) : 0.10000002384185791
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-12 : false
|
||||||
|
abs eps = 1e-9 : false
|
||||||
|
abs eps = 1e-3 : false
|
||||||
|
rel eps = 1e-12 : false
|
||||||
|
rel eps = 1e-9 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
3. Very small numbers: fixed absolute epsilon can be too large
|
||||||
|
============================================================
|
||||||
|
a : 9.9999999999999998e-13
|
||||||
|
b : 2e-12
|
||||||
|
abs(a - b) : 9.9999999999999998e-13
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-9 : true
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
rel eps = 1e-9 : false
|
||||||
|
rel eps = 0.5 : true
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
4. Near zero: relative comparison alone is weak
|
||||||
|
============================================================
|
||||||
|
a : 0
|
||||||
|
b : 1.0000000000000001e-15
|
||||||
|
abs(a - b) : 1.0000000000000001e-15
|
||||||
|
a == b : false
|
||||||
|
rel eps = 1e-6 : false
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
5. Same math on paper, different result in floating point
|
||||||
|
============================================================
|
||||||
|
x = (a + b) + c : 1
|
||||||
|
y = a + (b + c) : 0
|
||||||
|
abs(x - y) : 1
|
||||||
|
x == y : false
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
6. Accumulation of error: repeated addition
|
||||||
|
============================================================
|
||||||
|
x : 100000.00000133288
|
||||||
|
y : 100000
|
||||||
|
abs(x - y) : 1.3328826753422618e-06
|
||||||
|
x == y : false
|
||||||
|
abs eps = 1e-9 : false
|
||||||
|
abs eps = 1e-6 : false
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
7. float vs double: same idea, different precision
|
||||||
|
============================================================
|
||||||
|
float a : 0.30000001
|
||||||
|
float b : 0.30000001
|
||||||
|
float abs diff : 0
|
||||||
|
float a == b : true
|
||||||
|
|
||||||
|
double a : 0.30000000000000004
|
||||||
|
double b : 0.29999999999999999
|
||||||
|
double abs diff : 5.5511151231257827e-17
|
||||||
|
double a == b : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
8. Sensor-like values: 'equal' is often the wrong question
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.050000000000000003, abs_eps: 0.10000000000000001
|
||||||
|
sample value == abs comb
|
||||||
|
0 24.97779766 false true true
|
||||||
|
1 25.01916948 false true true
|
||||||
|
2 25.02972687 false true true
|
||||||
|
3 25.01870257 false true true
|
||||||
|
4 24.96365349 false true true
|
||||||
|
5 25.02417787 false true true
|
||||||
|
6 25.01521257 false true true
|
||||||
|
7 25.01746188 false true true
|
||||||
|
8 25.01469876 false true true
|
||||||
|
9 24.95849519 false true true
|
||||||
|
10 25.00975313 false true true
|
||||||
|
11 24.96665774 false true true
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.005, abs_eps: 0.01
|
||||||
|
sample value == abs comb
|
||||||
|
0 24.99675513 false true true
|
||||||
|
1 24.9971971 false true true
|
||||||
|
2 25.00143947 false true true
|
||||||
|
3 24.99902736 false true true
|
||||||
|
4 24.99946988 false true true
|
||||||
|
5 24.99607726 false true true
|
||||||
|
6 24.99667581 false true true
|
||||||
|
7 25.00177208 false true true
|
||||||
|
8 24.99822762 false true true
|
||||||
|
9 25.00066511 false true true
|
||||||
|
10 24.997119 false true true
|
||||||
|
11 25.0030632 false true true
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.0005, abs_eps: 0.0001
|
||||||
|
sample value == abs comb
|
||||||
|
0 24.99998171 false true true
|
||||||
|
1 25.00043692 false false false
|
||||||
|
2 24.99991995 false true true
|
||||||
|
3 24.99953881 false false false
|
||||||
|
4 24.99997226 false true true
|
||||||
|
5 25.00001312 false true true
|
||||||
|
6 24.99969943 false false false
|
||||||
|
7 25.00025024 false false false
|
||||||
|
8 24.99970481 false false false
|
||||||
|
9 25.0004967 false false false
|
||||||
|
10 24.99993727 false true true
|
||||||
|
11 24.99984134 false false false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
9. Scaled integer values: often better to compare raw domain
|
||||||
|
============================================================
|
||||||
|
raw_value : 1234
|
||||||
|
raw_target : 1234
|
||||||
|
raw_value == raw_target : true
|
||||||
|
|
||||||
|
scaled_value : 123.40000000000001
|
||||||
|
scaled_target : 123.40000000000001
|
||||||
|
abs diff : 0
|
||||||
|
scaled_value == scaled_target: true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
Note: if your system is naturally discrete, comparing raw units can be simpler
|
||||||
|
and more honest than converting everything to floating point too early.
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
10. Rounding is not a universal fix
|
||||||
|
============================================================
|
||||||
|
a : 1.0048999999999999
|
||||||
|
b : 1.0051000000000001
|
||||||
|
|
||||||
|
round(a, 2) : 1
|
||||||
|
round(b, 2) : 1.01
|
||||||
|
equal after round(2) : false
|
||||||
|
|
||||||
|
round(a, 3) : 1.0049999999999999
|
||||||
|
round(b, 3) : 1.0049999999999999
|
||||||
|
equal after round(3) : true
|
||||||
|
|
||||||
|
Rounding may hide differences or invent equality depending on chosen precision.
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
11. Hysteresis: in real systems you often want state logic, not equality
|
||||||
|
============================================================
|
||||||
|
step value simple_ctrl hyst_ctrl
|
||||||
|
0 24.92 HEATER ON HEATER ON
|
||||||
|
1 24.97 HEATER ON HEATER ON
|
||||||
|
2 25.01 HEATER OFF HEATER ON
|
||||||
|
3 25.05 HEATER OFF HEATER ON
|
||||||
|
4 24.99 HEATER ON HEATER ON
|
||||||
|
5 25.08 HEATER OFF HEATER ON
|
||||||
|
6 25.11 HEATER OFF HEATER OFF
|
||||||
|
7 25.06 HEATER OFF HEATER OFF
|
||||||
|
8 24.98 HEATER ON HEATER OFF
|
||||||
|
9 24.91 HEATER ON HEATER OFF
|
||||||
|
10 24.89 HEATER ON HEATER ON
|
||||||
|
11 24.95 HEATER ON HEATER ON
|
||||||
|
12 25.02 HEATER OFF HEATER ON
|
||||||
|
13 25.12 HEATER OFF HEATER OFF
|
||||||
|
14 25.07 HEATER OFF HEATER OFF
|
||||||
|
15 24.93 HEATER ON HEATER OFF
|
||||||
|
|
||||||
|
This is the key engineering point:
|
||||||
|
sometimes the answer is not a better equality test,
|
||||||
|
but a better control model.
|
||||||
|
|
||||||
|
Done.
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
|
||||||
|
============================================================
|
||||||
|
1. Basic classic: 0.1 + 0.2 != 0.3
|
||||||
|
============================================================
|
||||||
|
a : 0.30000000000000004
|
||||||
|
b : 0.29999999999999999
|
||||||
|
abs(a - b) : 5.5511151231257827e-17
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
abs eps = 1e-9 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
2. Large numbers: fixed absolute epsilon becomes useless
|
||||||
|
============================================================
|
||||||
|
a : 1000000000
|
||||||
|
b : 1000000000.1
|
||||||
|
abs(a - b) : 0.10000002384185791
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-12 : false
|
||||||
|
abs eps = 1e-9 : false
|
||||||
|
abs eps = 1e-3 : false
|
||||||
|
rel eps = 1e-12 : false
|
||||||
|
rel eps = 1e-9 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
3. Very small numbers: fixed absolute epsilon can be too large
|
||||||
|
============================================================
|
||||||
|
a : 9.9999999999999998e-13
|
||||||
|
b : 2e-12
|
||||||
|
abs(a - b) : 9.9999999999999998e-13
|
||||||
|
a == b : false
|
||||||
|
abs eps = 1e-9 : true
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
rel eps = 1e-9 : false
|
||||||
|
rel eps = 0.5 : true
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
4. Near zero: relative comparison alone is weak
|
||||||
|
============================================================
|
||||||
|
a : 0
|
||||||
|
b : 1.0000000000000001e-15
|
||||||
|
abs(a - b) : 1.0000000000000001e-15
|
||||||
|
a == b : false
|
||||||
|
rel eps = 1e-6 : false
|
||||||
|
abs eps = 1e-12 : true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
5. Same math on paper, different result in floating point
|
||||||
|
============================================================
|
||||||
|
x = (a + b) + c : 1
|
||||||
|
y = a + (b + c) : 0
|
||||||
|
abs(x - y) : 1
|
||||||
|
x == y : false
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
6. Accumulation of error: repeated addition
|
||||||
|
============================================================
|
||||||
|
x : 100000.00000133288
|
||||||
|
y : 100000
|
||||||
|
abs(x - y) : 1.3328826753422618e-06
|
||||||
|
x == y : false
|
||||||
|
abs eps = 1e-9 : false
|
||||||
|
abs eps = 1e-6 : false
|
||||||
|
combined : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
7. float vs double: same idea, different precision
|
||||||
|
============================================================
|
||||||
|
float a : 0.30000001
|
||||||
|
float b : 0.30000001
|
||||||
|
float abs diff : 0
|
||||||
|
float a == b : true
|
||||||
|
|
||||||
|
double a : 0.30000000000000004
|
||||||
|
double b : 0.29999999999999999
|
||||||
|
double abs diff : 5.5511151231257827e-17
|
||||||
|
double a == b : false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
8. Sensor-like values: 'equal' is often the wrong question
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.050000000000000003, abs_eps: 0.10000000000000001
|
||||||
|
sample value == abs comb
|
||||||
|
0 24.97471804 false true true
|
||||||
|
1 25.0413491 false true true
|
||||||
|
2 24.99852989 false true true
|
||||||
|
3 24.99317494 false true true
|
||||||
|
4 25.00292729 false true true
|
||||||
|
5 25.03122934 false true true
|
||||||
|
6 24.97063462 false true true
|
||||||
|
7 24.9619692 false true true
|
||||||
|
8 24.99279928 false true true
|
||||||
|
9 24.97964776 false true true
|
||||||
|
10 25.04053616 false true true
|
||||||
|
11 25.0353959 false true true
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.005, abs_eps: 0.01
|
||||||
|
sample value == abs comb
|
||||||
|
0 25.00020134 false true true
|
||||||
|
1 25.00382071 false true true
|
||||||
|
2 25.00383611 false true true
|
||||||
|
3 24.99614752 false true true
|
||||||
|
4 25.00265027 false true true
|
||||||
|
5 25.00074494 false true true
|
||||||
|
6 24.99856782 false true true
|
||||||
|
7 25.00364029 false true true
|
||||||
|
8 25.00150722 false true true
|
||||||
|
9 25.00310794 false true true
|
||||||
|
10 25.00211411 false true true
|
||||||
|
11 25.00197054 false true true
|
||||||
|
|
||||||
|
Noise amplitude: +/-0.0005, abs_eps: 0.0001
|
||||||
|
sample value == abs comb
|
||||||
|
0 25.00034068 false false false
|
||||||
|
1 24.99978583 false false false
|
||||||
|
2 24.99965013 false false false
|
||||||
|
3 25.00030996 false false false
|
||||||
|
4 25.00044598 false false false
|
||||||
|
5 25.00007675 false true true
|
||||||
|
6 25.00043085 false false false
|
||||||
|
7 24.99969316 false false false
|
||||||
|
8 24.99999024 false true true
|
||||||
|
9 24.99991615 false true true
|
||||||
|
10 25.00012491 false false false
|
||||||
|
11 24.99951951 false false false
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
9. Scaled integer values: often better to compare raw domain
|
||||||
|
============================================================
|
||||||
|
raw_value : 1234
|
||||||
|
raw_target : 1234
|
||||||
|
raw_value == raw_target : true
|
||||||
|
|
||||||
|
scaled_value : 123.40000000000001
|
||||||
|
scaled_target : 123.40000000000001
|
||||||
|
abs diff : 0
|
||||||
|
scaled_value == scaled_target: true
|
||||||
|
combined : true
|
||||||
|
|
||||||
|
Note: if your system is naturally discrete, comparing raw units can be simpler
|
||||||
|
and more honest than converting everything to floating point too early.
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
10. Rounding is not a universal fix
|
||||||
|
============================================================
|
||||||
|
a : 1.0048999999999999
|
||||||
|
b : 1.0051000000000001
|
||||||
|
|
||||||
|
round(a, 2) : 1
|
||||||
|
round(b, 2) : 1.01
|
||||||
|
equal after round(2) : false
|
||||||
|
|
||||||
|
round(a, 3) : 1.0049999999999999
|
||||||
|
round(b, 3) : 1.0049999999999999
|
||||||
|
equal after round(3) : true
|
||||||
|
|
||||||
|
Rounding may hide differences or invent equality depending on chosen precision.
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
11. Hysteresis: in real systems you often want state logic, not equality
|
||||||
|
============================================================
|
||||||
|
step value simple_ctrl hyst_ctrl
|
||||||
|
0 24.92 HEATER ON HEATER ON
|
||||||
|
1 24.97 HEATER ON HEATER ON
|
||||||
|
2 25.01 HEATER OFF HEATER ON
|
||||||
|
3 25.05 HEATER OFF HEATER ON
|
||||||
|
4 24.99 HEATER ON HEATER ON
|
||||||
|
5 25.08 HEATER OFF HEATER ON
|
||||||
|
6 25.11 HEATER OFF HEATER OFF
|
||||||
|
7 25.06 HEATER OFF HEATER OFF
|
||||||
|
8 24.98 HEATER ON HEATER OFF
|
||||||
|
9 24.91 HEATER ON HEATER OFF
|
||||||
|
10 24.89 HEATER ON HEATER ON
|
||||||
|
11 24.95 HEATER ON HEATER ON
|
||||||
|
12 25.02 HEATER OFF HEATER ON
|
||||||
|
13 25.12 HEATER OFF HEATER OFF
|
||||||
|
14 25.07 HEATER OFF HEATER OFF
|
||||||
|
15 24.93 HEATER ON HEATER OFF
|
||||||
|
|
||||||
|
This is the key engineering point:
|
||||||
|
sometimes the answer is not a better equality test,
|
||||||
|
but a better control model.
|
||||||
|
|
||||||
|
Done.
|
||||||
251
analysis/02-Floating_Point_Equality_Is_a_Lie/readme.md
Normal file
251
analysis/02-Floating_Point_Equality_Is_a_Lie/readme.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# 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 isn’t.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
- example/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
|
||||||
|
|
||||||
|
see example/*.txt files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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.
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# Analysis #XX — Two Sum Is Not About Numbers
|
||||||
|
|
||||||
|
## Problem (LeetCode-style)
|
||||||
|
|
||||||
|
You are given a list of records. Each record contains:
|
||||||
|
|
||||||
|
- an identifier
|
||||||
|
- a value
|
||||||
|
- optional metadata
|
||||||
|
|
||||||
|
Your task is to find whether there exists a pair of records whose values sum to a given target.
|
||||||
|
|
||||||
|
Return the identifiers of any such pair.
|
||||||
|
|
||||||
|
Constraints:
|
||||||
|
- Each record may be used at most once
|
||||||
|
- At most one valid answer exists
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Typical Interview Thinking
|
||||||
|
|
||||||
|
1. Start with brute force:
|
||||||
|
- Check all pairs → O(n²)
|
||||||
|
|
||||||
|
2. Optimize:
|
||||||
|
- Use a hash map
|
||||||
|
- Store seen values
|
||||||
|
- Lookup complement (target - value)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
unordered_map<int, int> seen;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
int complement = target - nums[i];
|
||||||
|
|
||||||
|
if (seen.count(complement)) {
|
||||||
|
return {seen[complement], i};
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[nums[i]] = i;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Time complexity: O(n)
|
||||||
|
Space complexity: O(n)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Actually Tests
|
||||||
|
|
||||||
|
- Pattern recognition
|
||||||
|
- Familiarity with hash maps
|
||||||
|
- Knowledge of time complexity
|
||||||
|
- Prior exposure to the problem
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real-World Version (Logs & Event Correlation)
|
||||||
|
|
||||||
|
### Synthetic Log Example
|
||||||
|
|
||||||
|
```
|
||||||
|
2026-04-16T10:15:01.123Z service=api event=parse_input latency=12ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.130Z service=cache event=cache_miss latency=48ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.135Z service=db event=read_user latency=55ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.144Z service=net event=external_call latency=47ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.151Z service=cache event=cache_miss latency=60ms request_id=req-3001
|
||||||
|
2026-04-16T10:15:01.154Z service=net event=external_call latency=52ms request_id=req-3001
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real Problem
|
||||||
|
|
||||||
|
Detect whether there exist two events:
|
||||||
|
|
||||||
|
- belonging to the same request_id
|
||||||
|
- occurring within a time window
|
||||||
|
- whose combined latency exceeds a threshold
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Where LeetCode Logic Breaks
|
||||||
|
|
||||||
|
### 1. Not Exact Match
|
||||||
|
LeetCode:
|
||||||
|
```
|
||||||
|
a + b == target
|
||||||
|
```
|
||||||
|
|
||||||
|
Reality:
|
||||||
|
```
|
||||||
|
a + b > threshold
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Context Matters (request_id)
|
||||||
|
|
||||||
|
You cannot mix unrelated events.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Time Window
|
||||||
|
|
||||||
|
Events must be close in time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Streaming Data
|
||||||
|
|
||||||
|
- Data arrives continuously
|
||||||
|
- May be out of order
|
||||||
|
- Cannot store everything
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real Engineering Approach
|
||||||
|
|
||||||
|
### Core Idea
|
||||||
|
|
||||||
|
Maintain sliding windows per request_id.
|
||||||
|
|
||||||
|
### Pseudocode
|
||||||
|
|
||||||
|
```
|
||||||
|
for each incoming event:
|
||||||
|
bucket = active_events[event.request_id]
|
||||||
|
|
||||||
|
remove old events outside time window
|
||||||
|
|
||||||
|
for each old_event in bucket:
|
||||||
|
if event.latency + old_event.latency > threshold:
|
||||||
|
report anomaly
|
||||||
|
|
||||||
|
add event to bucket
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Real Constraints
|
||||||
|
|
||||||
|
- Out-of-order events
|
||||||
|
- Missing logs
|
||||||
|
- Duplicate events
|
||||||
|
- Noise filtering
|
||||||
|
- Memory limits
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Takeaway
|
||||||
|
|
||||||
|
Two Sum is not about numbers.
|
||||||
|
|
||||||
|
It is about recognizing patterns in controlled environments.
|
||||||
|
|
||||||
|
Real engineering problems are about:
|
||||||
|
|
||||||
|
- defining valid data
|
||||||
|
- handling imperfect inputs
|
||||||
|
- managing time and memory
|
||||||
|
- maintaining system behavior under constraints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Perspective
|
||||||
|
|
||||||
|
Exists in real engineering?
|
||||||
|
→ Yes, but heavily transformed
|
||||||
|
|
||||||
|
Exists in interview form?
|
||||||
|
→ Yes, but oversimplified
|
||||||
251
analysis/03-Two_Sum_Is_Not_About_Numbers/readme.md
Normal file
251
analysis/03-Two_Sum_Is_Not_About_Numbers/readme.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# Analysis #XX — Two Sum Is Not About Numbers
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
At first glance, the problem looks trivial:
|
||||||
|
|
||||||
|
> Given a list of values, find two elements whose sum equals a target.
|
||||||
|
|
||||||
|
This is one of the most well-known interview questions, commonly referred to as **Two Sum**.
|
||||||
|
|
||||||
|
It is simple, clean, and perfectly defined:
|
||||||
|
- a static array
|
||||||
|
- exact arithmetic
|
||||||
|
- a guaranteed answer
|
||||||
|
|
||||||
|
And that’s exactly why it works so well in interviews.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Typical Interview Thinking
|
||||||
|
|
||||||
|
A candidate is expected to go through a familiar progression:
|
||||||
|
|
||||||
|
1. Start with brute force (O(n²))
|
||||||
|
2. Recognize inefficiency
|
||||||
|
3. Optimize using a hash map
|
||||||
|
4. Achieve O(n) time complexity
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
unordered_map<int, int> seen;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
int complement = target - nums[i];
|
||||||
|
|
||||||
|
if (seen.count(complement)) {
|
||||||
|
return {seen[complement], i};
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[nums[i]] = i;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The “correct” answer is not about solving the problem.
|
||||||
|
|
||||||
|
It is about recognizing the pattern.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Actually Tests
|
||||||
|
|
||||||
|
Despite its simplicity, this problem evaluates:
|
||||||
|
|
||||||
|
- familiarity with standard patterns
|
||||||
|
- ability to choose a data structure
|
||||||
|
- understanding of time complexity
|
||||||
|
|
||||||
|
But most importantly:
|
||||||
|
|
||||||
|
> it tests whether you have seen this problem before.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A Subtle Shift
|
||||||
|
|
||||||
|
Now let’s take the same idea and move it one step closer to reality.
|
||||||
|
|
||||||
|
Instead of numbers, we have **log events**.
|
||||||
|
|
||||||
|
Instead of a static array, we have a **stream**.
|
||||||
|
|
||||||
|
Instead of a clean equality, we have **imperfect data and thresholds**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Synthetic Log Example
|
||||||
|
|
||||||
|
```
|
||||||
|
2026-04-16T10:15:01.123Z service=api event=parse_input latency=12ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.130Z service=cache event=cache_miss latency=48ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.135Z service=db event=read_user latency=55ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.144Z service=net event=external_call latency=47ms request_id=req-1001
|
||||||
|
2026-04-16T10:15:01.151Z service=cache event=cache_miss latency=60ms request_id=req-3001
|
||||||
|
2026-04-16T10:15:01.154Z service=net event=external_call latency=52ms request_id=req-3001
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real Problem
|
||||||
|
|
||||||
|
We are no longer asked to find two numbers.
|
||||||
|
|
||||||
|
Instead, the problem becomes:
|
||||||
|
|
||||||
|
> Detect whether there exist two events:
|
||||||
|
> - belonging to the same request
|
||||||
|
> - occurring close in time
|
||||||
|
> - whose combined latency exceeds a threshold
|
||||||
|
|
||||||
|
This still *looks* like Two Sum.
|
||||||
|
|
||||||
|
But it is not.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Where the Interview Model Breaks
|
||||||
|
|
||||||
|
### 1. No Exact Match
|
||||||
|
|
||||||
|
Interview version:
|
||||||
|
```
|
||||||
|
a + b == target
|
||||||
|
```
|
||||||
|
|
||||||
|
Real version:
|
||||||
|
```
|
||||||
|
a + b > threshold
|
||||||
|
```
|
||||||
|
|
||||||
|
We are not searching for a perfect complement.
|
||||||
|
We are evaluating a condition.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Context Is Mandatory
|
||||||
|
|
||||||
|
You cannot combine arbitrary events.
|
||||||
|
|
||||||
|
A latency spike only makes sense **within the same request**.
|
||||||
|
|
||||||
|
Without context, the result is meaningless.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Time Matters
|
||||||
|
|
||||||
|
Events are not just values — they exist in time.
|
||||||
|
|
||||||
|
Two events five seconds apart may not be related at all.
|
||||||
|
|
||||||
|
This introduces:
|
||||||
|
- time windows
|
||||||
|
- ordering issues
|
||||||
|
- temporal constraints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Data Is Not Static
|
||||||
|
|
||||||
|
LeetCode assumes:
|
||||||
|
- full dataset
|
||||||
|
- already loaded
|
||||||
|
- perfectly ordered
|
||||||
|
|
||||||
|
Reality:
|
||||||
|
- streaming input
|
||||||
|
- delayed events
|
||||||
|
- missing entries
|
||||||
|
- out-of-order delivery
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What the Problem Really Becomes
|
||||||
|
|
||||||
|
At this point, the challenge is no longer:
|
||||||
|
|
||||||
|
> “find two numbers”
|
||||||
|
|
||||||
|
It becomes:
|
||||||
|
|
||||||
|
> “determine which events are comparable at all”
|
||||||
|
|
||||||
|
And that is a fundamentally different problem.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Real Engineering Approach
|
||||||
|
|
||||||
|
Instead of solving a mathematical puzzle, we build a system.
|
||||||
|
|
||||||
|
### Core Idea
|
||||||
|
|
||||||
|
Maintain a sliding window of recent events per request.
|
||||||
|
|
||||||
|
### Pseudocode
|
||||||
|
|
||||||
|
```
|
||||||
|
for each incoming event:
|
||||||
|
bucket = active_events[event.request_id]
|
||||||
|
|
||||||
|
remove events outside time window
|
||||||
|
|
||||||
|
for each old_event in bucket:
|
||||||
|
if event.latency + old_event.latency > threshold:
|
||||||
|
report anomaly
|
||||||
|
|
||||||
|
add event to bucket
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Introduces
|
||||||
|
|
||||||
|
Now we must deal with:
|
||||||
|
|
||||||
|
- bounded memory
|
||||||
|
- streaming constraints
|
||||||
|
- time-based eviction
|
||||||
|
- correlation logic
|
||||||
|
|
||||||
|
And beyond that:
|
||||||
|
|
||||||
|
- out-of-order events
|
||||||
|
- duplicate logs
|
||||||
|
- partial data
|
||||||
|
- noise filtering
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Real Insight
|
||||||
|
|
||||||
|
The difficulty is not in computing a sum.
|
||||||
|
|
||||||
|
The difficulty is in defining:
|
||||||
|
|
||||||
|
- what data is valid
|
||||||
|
- what events belong together
|
||||||
|
- what “close enough” means
|
||||||
|
- how the system behaves under imperfect conditions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Takeaway
|
||||||
|
|
||||||
|
Two Sum is often presented as a problem about numbers.
|
||||||
|
|
||||||
|
In reality, it is a problem about assumptions.
|
||||||
|
|
||||||
|
Remove those assumptions, and the problem changes completely.
|
||||||
|
|
||||||
|
> The challenge is not finding two values.
|
||||||
|
> The challenge is understanding whether those values should ever be compared.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Perspective
|
||||||
|
|
||||||
|
Exists in real engineering?
|
||||||
|
→ Yes, but as event correlation under constraints
|
||||||
|
|
||||||
|
Exists in interview form?
|
||||||
|
→ Yes, but stripped of context and complexity
|
||||||
206
readme.md
Normal file
206
readme.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Beyond Interviews
|
||||||
|
|
||||||
|
## Real Engineering Problems
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why This Project Exists
|
||||||
|
|
||||||
|
Modern coding interviews often reward:
|
||||||
|
|
||||||
|
* pattern recognition
|
||||||
|
* memorized solutions
|
||||||
|
* speed under pressure
|
||||||
|
|
||||||
|
Real engineering rewards something very different:
|
||||||
|
|
||||||
|
* dealing with imperfect data
|
||||||
|
* understanding systems
|
||||||
|
* debugging unknown behavior
|
||||||
|
* making trade-offs under constraints
|
||||||
|
|
||||||
|
This project explores the gap between the two.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Is This Project About?
|
||||||
|
|
||||||
|
This project analyzes common interview-style problems (LeetCode, Codility, etc.) and asks a simple question:
|
||||||
|
|
||||||
|
> Do these problems reflect real engineering work?
|
||||||
|
|
||||||
|
Not in a negative or dismissive way — but in a practical, engineering-focused way.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Idea
|
||||||
|
|
||||||
|
Typical hiring pipeline:
|
||||||
|
|
||||||
|
```
|
||||||
|
Resume → Algorithmic Interview → Engineering Job
|
||||||
|
```
|
||||||
|
|
||||||
|
Each stage evaluates very different skills.
|
||||||
|
|
||||||
|
### Interview Tasks Evaluate:
|
||||||
|
|
||||||
|
* Algorithm knowledge
|
||||||
|
* Pattern recognition
|
||||||
|
* Speed and familiarity
|
||||||
|
* Data structures
|
||||||
|
|
||||||
|
### Real Engineering Requires:
|
||||||
|
|
||||||
|
* System design
|
||||||
|
* Working with imperfect inputs
|
||||||
|
* Debugging complex behavior
|
||||||
|
* Constraints (memory, latency, hardware)
|
||||||
|
* Trade-offs
|
||||||
|
* Maintainability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Project Does
|
||||||
|
|
||||||
|
For each problem, we:
|
||||||
|
|
||||||
|
1. Show the typical interview solution
|
||||||
|
2. Analyze what it actually tests
|
||||||
|
3. Show where it breaks
|
||||||
|
4. Map it to real-world engineering
|
||||||
|
5. Provide runnable examples (when relevant)
|
||||||
|
6. Discuss better approaches
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Philosophy
|
||||||
|
|
||||||
|
* No toxicity
|
||||||
|
* No complaints about interviews
|
||||||
|
* Focus on understanding, not blaming
|
||||||
|
* Respect both sides: interviews *and* engineering
|
||||||
|
* Show limitations **and** value
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Embedded & Systems Perspective
|
||||||
|
|
||||||
|
Most discussions about interview problems ignore real-world constraints.
|
||||||
|
|
||||||
|
This project does not.
|
||||||
|
|
||||||
|
We focus on:
|
||||||
|
|
||||||
|
* Bit-level data parsing
|
||||||
|
* CAN / J1939-like data flows
|
||||||
|
* Sensor noise and drift
|
||||||
|
* Floating point precision issues
|
||||||
|
* Memory constraints
|
||||||
|
* Real-time behavior
|
||||||
|
* Hardware interaction
|
||||||
|
|
||||||
|
These are common in real systems — and rarely represented in interviews.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example Direction
|
||||||
|
|
||||||
|
| Interview Problem | Real Engineering Equivalent |
|
||||||
|
| ----------------------- | ------------------------------------- |
|
||||||
|
| Two Sum | Event correlation in streams |
|
||||||
|
| Floating-point equality | Sensor comparison, tolerance handling |
|
||||||
|
| Array problems | Buffers, pipelines, streaming data |
|
||||||
|
| Graph traversal | State machines, routing, dependencies |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
analysis/
|
||||||
|
01-...
|
||||||
|
02-...
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Each analysis contains:
|
||||||
|
|
||||||
|
* Problem description
|
||||||
|
* Typical solution
|
||||||
|
* Failure scenarios
|
||||||
|
* Real-world context
|
||||||
|
* Demo code (optional)
|
||||||
|
* Key takeaway
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
Event-driven:
|
||||||
|
|
||||||
|
```
|
||||||
|
Problem ready → Publish
|
||||||
|
```
|
||||||
|
|
||||||
|
No artificial schedule.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Publishing Strategy
|
||||||
|
|
||||||
|
Initial phase:
|
||||||
|
|
||||||
|
* Prepare 2–4 analyses
|
||||||
|
* Establish consistency
|
||||||
|
|
||||||
|
Then:
|
||||||
|
|
||||||
|
* Publish repository
|
||||||
|
* Share insights (e.g., LinkedIn)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tone & Style
|
||||||
|
|
||||||
|
* Professional
|
||||||
|
* Clear and accessible
|
||||||
|
* Engineering-focused
|
||||||
|
* Minimal jargon when possible
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Question
|
||||||
|
|
||||||
|
Each analysis answers:
|
||||||
|
|
||||||
|
> Would this problem appear in real engineering?
|
||||||
|
|
||||||
|
Possible answers:
|
||||||
|
|
||||||
|
* Yes (rarely)
|
||||||
|
* Partially (in modified form)
|
||||||
|
* Almost never
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Long-Term Vision
|
||||||
|
|
||||||
|
This project may evolve into:
|
||||||
|
|
||||||
|
* A structured knowledge base
|
||||||
|
* A series of engineering articles
|
||||||
|
* A reference for improving interview practices
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final Note
|
||||||
|
|
||||||
|
This project is both:
|
||||||
|
|
||||||
|
* A personal exploration
|
||||||
|
* A contribution to the engineering community
|
||||||
|
|
||||||
|
It turns interview preparation into something more meaningful:
|
||||||
|
|
||||||
|
**understanding how real systems actually behave.**
|
||||||
Reference in New Issue
Block a user