Project 5.08 Section 5 ⚡ Embedded Relevance: Core Integer Division Truncation Rounding Math Fixed-Point Arithmetic

5.08 Integer Division Truncation vs Fixed-Point Scaling & Rounding Invariants

Executive Summary: Calculating statistical averages. We explore integer division truncation, precision loss in sensor data processing, and rounding strategies in integer arithmetic (e.g. (sum + N/2) / N).

💻 1. Annotated Source Code

#include <iostream>
using namespace std;

double average(double a, double b, double c);

int main() {
	double s1 = 91.2, s2 = 87.8, s3 = 79.6;

	double result = average(s1, s2, s3);

	cout << "The average score is: " << result << endl;

	return 0;
}

double average(double a, double b, double c) {
	return (a + b + c) / 3;
}

📐 2. Architecture & UML Class Model

📐 Average Calculation Function & Register Optimization
+ Public - Private # Protected
<<compilation-unit>> AverageFunctionModule Function Pipeline
(none / stateless)
+averageThree(a: double, b: double, c: double) : double

📚 3. Core C++ Concepts Deep-Dive

1. Integer Division Truncation

In C++, dividing two integers truncates toward zero (7 / 3 = 2), discarding fractional remainders.

2. Correct Integer Rounding Idiom

To round to the nearest integer instead of truncating, add half the divisor before dividing: (sum + (N / 2)) / N.

⚡ 4. Embedded Systems & Hardware Reality

1. Sensor Sampling Precision Loss

Raw ADC readings averaged via integer math suffer cumulative truncation bias. Fixed-point scaling (e.g. multiplying by 1000 before division) preserves millivolt precision without requiring floating-point calculations.

💡 5. Production-Ready Embedded Refactoring

Properly rounded integer average:

💡 Production-Ready Refactor
#include <cstdint>

// Integer average with nearest-integer rounding
constexpr uint32_t averageThreeRounded(uint32_t a, uint32_t b, uint32_t c) noexcept {
    return (a + b + c + 1) / 3; // Adding divisor/2 (1 for divisor 3) rounds correctly
}

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. What is the result of the C++ integer expression '10 / 4'?
A 2 (truncated toward zero)
B 2.5
C 3 (rounded up)
D 0
Detailed Explanation: Integer division in C++ discards fractional remainders, yielding 2.
Q2. How do you achieve nearest-integer rounding when dividing an integer 'sum' by 'N' in integer arithmetic?
A (sum + (N / 2)) / N
B sum / N + 0.5
C (sum * N) / 2
D sum % N
Detailed Explanation: Adding half the divisor (N / 2) before dividing rounds values $\ge 0.5$ up to the next integer.
Q3. Why should sensor ADC averaging avoid pure floating-point math on small microcontrollers?
A Floating-point division is slow and non-deterministic on MCUs without an FPU, whereas scaled integer math executes in single-digit clock cycles
B Float math destroys ADC calibration
C Floats cannot hold numbers smaller than 1
D Floating point math only works on Linux
Detailed Explanation: Integer math executes rapidly on all microcontrollers; fixed-point scaling preserves precision without the cycle overhead of software float emulation.
Q4. What is the risk of calculating '(a + b + c) / 3' when a, b, and c are large uint32_t values near 2^32 - 1?
A Integer overflow occurs during the addition before division takes place, producing a completely incorrect result
B The division fails with a CPU exception
C The compiler converts them to negative integers
D The compiler reorders the terms to prevent overflow
Detailed Explanation: Summing large integers can overflow 32 bits before division. Using 64-bit accumulators (uint64_t) prevents overflow.