Project 5.07 Section 5 ⚡ Embedded Relevance: Core Bitwise & Modulo % Branchless Condition Codes Optimization

5.07 Modulo (%) vs Bitwise AND (& 1) & Branchless Counting in Assembly

Executive Summary: Analyzing parity checks and filtering in arrays. We contrast expensive hardware division (num % 2) with single-cycle bitwise operations (num & 1) and demonstrate branchless arithmetic algorithms that eliminate pipeline flushes.

💻 1. Annotated Source Code

#include <iostream>
using namespace std;

int countEvens(int arr[], int size);

int main() {

	int myArray[] = { 12, 7, 4, 19, 22, 3, 8, 10 };

	int numEvens = countEvens(myArray, 8);

	cout << "Number of even elements: " << numEvens << endl;

	return 0;
}

int countEvens(int arr[], int size) {
	int count = 0;

	for (int i = 0; i < size; i++) {
		if (arr[i] % 2 == 0) {
			count++;
		}
	}

	return count;
}

📐 2. Architecture & UML Class Model

📐 Array Event Filtering & Branchless Counting Model
+ Public - Private # Protected
<<compilation-unit>> EvenCounterEngine Counting ALU
(none / stateless)
+countEvens(arr: const int*, size: size_t) : size_t
+countEvensBranchless(arr: const int*, size: size_t) : size_t

📚 3. Core C++ Concepts Deep-Dive

1. Parity Checking: Modulo vs Bitwise

In standard arithmetic, even numbers satisfy num % 2 == 0. In binary representations, the Least Significant Bit (LSB) determines parity: (num & 1) == 0.

⚡ 4. Embedded Systems & Hardware Reality

1. Hardware Division vs Bitwise Masking

On microcontrollers lacking hardware division (e.g. ARM Cortex-M0), modulo division (%) calls software division routines (__aeabi_idivmod) taking 20-50 cycles. Bitwise AND (& 1) executes in 1 clock cycle.

2. Branchless Counting

By computing count += (val & 1) ^ 1, code runs without if statements, eliminating CPU pipeline branch stalls.

💡 5. Production-Ready Embedded Refactoring

Branchless even-number counter:

💡 Production-Ready Refactor
#include <cstdint>
#include <cstddef>

size_t countEvensBranchless(const uint32_t* data, size_t len) noexcept {
    size_t count = 0;
    for (size_t i = 0; i < len; ++i) {
        // Branchless: (data[i] & 1) is 0 for even, 1 for odd
        count += (data[i] & 1) ^ 1;
    }
    return count;
}

📝 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 is '(num & 1) == 0' preferred over 'num % 2 == 0' on low-power microcontrollers?
A Bitwise AND is a single-cycle ALU instruction, whereas modulo may require expensive hardware or software division
B Modulo only works with positive floating-point numbers
C Bitwise AND prevents memory leaks
D Modulo requires heap memory allocation
Detailed Explanation: Bitwise masking checks the least significant bit in 1 clock cycle, avoiding costly division instructions.
Q2. What is the advantage of 'branchless programming' in high-speed firmware?
A It replaces conditional jump branches with arithmetic instructions, preventing CPU pipeline stalls and branch misprediction penalties
B It makes C++ code look shorter
C It removes the need for functions
D It runs without a power supply
Detailed Explanation: Branchless code eliminates if branches, ensuring the CPU pipeline flows smoothly without stalls caused by branch mispredictions.
Q3. What does '(val & 1) ^ 1' evaluate to when val is an even integer (e.g. 4)?
A 1 (true)
B 0 (false)
C 4
D 2
Detailed Explanation: For even numbers: val & 1 = 0. Then 0 ^ 1 = 1.
Q4. Which ARM Cortex-M core lacks a hardware integer divide instruction (SDIV/UDIV)?
A ARM Cortex-M0 / Cortex-M0+
B ARM Cortex-M3
C ARM Cortex-M4
D ARM Cortex-M7
Detailed Explanation: ARM Cortex-M0 and M0+ cores omit hardware division hardware to minimize silicon area and power consumption.