2.12 Integer Ratio Division, Order of Operations & Multiply-Before-Divide Scaling
Executive Summary: Calculating percentage ratios from integer variables. We examine the classic beginner integer division pitfall (e.g. (count / total) * 100 evaluating to 0), enforce the Multiply-Before-Divide rule, and protect against 32-bit overflow using 64-bit intermediate accumulators.
💻 1. Annotated Source Code
#include <iostream> #include <string> using namespace std; int main() { string fullName; string location; int initialScore; cout << "Please enter your full name: " << endl; getline(cin, fullName); cout << "Please enter your city, state/province, and country: " << endl; getline(cin, location); cout << "Please enter your score (0 to 100): " << endl; cin >> initialScore; cout << "Hello, " << fullName << endl; cout << "We heard you are from " << location << endl; cout << "Your original score is " << initialScore << ", but with five points added, your score is " << (initialScore + 5) << endl; return 0; }
📐 2. Architecture & UML Class Model
<<compilation-unit>>
PercentageCalculator
Math Pipeline
Attributes / Data Members
-numerator : double
-denominator : double
Operations / Methods
+calculatePercentage(num: double, den: double) : double
+calculateBpsFixedPoint(num: int32_t, den: int32_t) : int32_t
📚 3. Core C++ Concepts Deep-Dive
1. The Zero-Result Pitfall
In integer arithmetic, evaluating (part / total) * 100 performs integer division first. When part < total, part / total truncates to 0, resulting in 0 * 100 = 0%!
2. The Multiply-Before-Divide Rule
To preserve precision, always multiply first: (part * 100) / total.
⚡ 4. Embedded Systems & Hardware Reality
1. Preventing Intermediate Overflow
Multiplying part * 100 can overflow 32-bit integer limits if part > 42,949,672. Casting to uint64_t during the multiplication step guarantees 100% overflow immunity.
💡 5. Production-Ready Embedded Refactoring
Safe, high-precision integer percentage calculation:
💡 Production-Ready Refactor
#include <cstdint> // Calculates percentage (0-100%) with 0 float overhead and 0 overflow risk constexpr uint32_t calculatePercentage(uint32_t part, uint32_t total) noexcept { if (total == 0) return 0; // 64-bit promotion prevents 32-bit intermediate multiplication overflow return static_cast<uint32_t>((static_cast<uint64_t>(part) * 100UL) / total); }
📝 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. Why does the C++ integer expression '(5 / 10) * 100' evaluate to 0 instead of 50?
Detailed Explanation:
Because division occurs first, $5/10 = 0$ in integer arithmetic. Then $0 \times 100 = 0$.
Q2. What is the 'Multiply-Before-Divide' rule in fixed-point and integer embedded math?
Detailed Explanation:
Multiplying before dividing preserves resolution in the upper bits before integer truncation occurs.
Q3. What is the danger of '(part * 1000) / total' when 'part' is a large uint32_t variable?
Detailed Explanation:
If $part \times 1000 > 2^{32}-1$, 32-bit overflow occurs. Casting to
uint64_t before multiplication prevents this.
Q4. How do you calculate basis points (0.01% resolution, e.g. 5000 = 50.00%) using integer math?
Detailed Explanation:
Multiplying by 10,000 provides $1/10,000$ ($0.01\%$) resolution with integer arithmetic.