Compare commits

...

16 Commits

Author SHA1 Message Date
269d560847 second 2026-04-16 20:41:31 -04:00
9ad604196e #1 intial version 2026-04-16 20:34:21 -04:00
b14ef0beca fixed example output. 2026-03-28 16:47:02 -04:00
f279ec4ff3 closes #5 2026-03-28 15:58:38 -04:00
d1d2109d13 Why LeetCode Problems Don't Reflect Real Engineering 2026-03-28 15:57:40 -04:00
4fdcf67b0a some changes 2026-03-28 09:14:39 -04:00
8408537b81 rename file 2026-03-28 09:13:07 -04:00
140145c257 fixed example path 2026-03-28 08:57:51 -04:00
d6084d6aea fixed file name 2026-03-28 08:56:51 -04:00
52114dae41 makefile based build 2026-03-28 08:55:31 -04:00
244dc0afa6 use ascii 2026-03-28 08:45:48 -04:00
91a2f7b159 rename 2026-03-28 08:40:25 -04:00
bc6a0f942e rename folder 2026-03-28 08:39:53 -04:00
0cbdf699f1 rename 2026-03-28 08:38:45 -04:00
3a5ca9d5b1 #02 — Floating Point Equality Is a Lie 2026-03-28 08:26:11 -04:00
831f7f0215 coding style fix 2026-03-28 08:21:02 -04:00
12 changed files with 1945 additions and 139 deletions

135
README.md
View File

@@ -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 dont
---
## 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.

View File

@@ -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 510 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 1020 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.

View File

@@ -195,15 +195,13 @@ Wait for valid data.
```cpp
auto result = safe_add(a, b);
if (result.invalid)
{
if (result.invalid) {
publish_invalid();
error_counter++;
return;
}
if (result.value > c)
{
if (result.value > c) {
update_state();
}
```

View File

@@ -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

View File

@@ -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

View 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;
}

View File

@@ -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.

View File

@@ -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.

View 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 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:
- 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.

View File

@@ -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

View 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 thats 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 lets 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
View 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 24 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.**