Fixed-point arithmetic for embedded DSP in Signal Processing - Time & Space Complexity
When working with fixed-point arithmetic in embedded DSP, it is important to understand how the time to perform calculations changes as the data size grows.
We want to know how the number of operations grows when processing more data points.
Analyze the time complexity of the following fixed-point multiply-accumulate operation over an input array.
// Fixed-point multiply-accumulate on input array
int32_t fixed_point_mac(int16_t *input, int16_t *coeff, int n) {
int32_t acc = 0;
for (int i = 0; i < n; i++) {
acc += (int32_t)input[i] * (int32_t)coeff[i];
}
return acc;
}
This code multiplies each input value by a coefficient and sums the results using fixed-point arithmetic.
- Primary operation: The for-loop that multiplies and accumulates each pair of input and coefficient values.
- How many times: Exactly n times, where n is the size of the input arrays.
Each additional data point adds one multiply and one add operation, so the total work grows directly with the number of data points.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 multiply-accumulate steps |
| 100 | 100 multiply-accumulate steps |
| 1000 | 1000 multiply-accumulate steps |
Pattern observation: The number of operations increases in a straight line as input size grows.
Time Complexity: O(n)
This means the time to complete the fixed-point multiply-accumulate grows directly in proportion to the number of data points.
[X] Wrong: "The multiply-accumulate operation takes constant time regardless of input size because it is a simple calculation."
[OK] Correct: While one multiply-accumulate is quick, the code repeats it for every data point, so total time grows with the number of points.
Understanding how loops over data affect time is key in embedded DSP tasks, showing you can reason about performance in real systems.
"What if we added a nested loop inside the multiply-accumulate to process pairs of coefficients for each input? How would the time complexity change?"
Practice
Solution
Step 1: Understand fixed-point arithmetic purpose
Fixed-point arithmetic is used to perform calculations efficiently on devices that lack floating-point hardware.Step 2: Compare options with this purpose
To perform fast math on devices without floating-point hardware correctly states the main reason: fast math on devices without floating-point units. Other options are incorrect because fixed-point does not increase precision beyond floating-point, does not simplify programming by avoiding scaling, and does not use more memory.Final Answer:
To perform fast math on devices without floating-point hardware -> Option BQuick Check:
Fixed-point speeds math on limited hardware = A [OK]
- Thinking fixed-point increases precision beyond floating-point
- Assuming fixed-point uses more memory
- Believing fixed-point avoids scaling complexity
Solution
Step 1: Understand fixed-point scaling
For 8 fractional bits, multiply the integer value by 2^8 (which is shifting left by 8) to convert to fixed-point.Step 2: Match with options
int16_t fixed = value << 8; shifts left by 8 bits, correctly scaling the value. int16_t fixed = value >> 8; shifts right (wrong direction), A divides by 8 (wrong), C multiplies by 8 (not 256).Final Answer:
int16_t fixed = value << 8; -> Option AQuick Check:
Shift left by fractional bits to scale = D [OK]
- Shifting right instead of left
- Multiplying/dividing by wrong powers of two
- Confusing fractional bits with decimal places
a = 0x0100 (1.0) and b = 0x0200 (2.0), what is the fixed-point result of c = (a * b) >> 8;?Solution
Step 1: Multiply fixed-point values
a * b = 0x0100 * 0x0200 = 256 * 512 = 131072 (decimal)Step 2: Adjust scale by shifting right 8 bits
c = 131072 >> 8 = 131072 / 256 = 512 decimal = 0x0200Step 3: Recalculate carefully
Wait, 0x0100 = 256 decimal, 0x0200 = 512 decimal. Multiplying: 256 * 512 = 131072 decimal. Shifting right 8 bits divides by 256: 131072 / 256 = 512 decimal = 0x0200. So c = 0x0200 (2.0).Final Answer:
0x0200 (2.0) -> Option CQuick Check:
(1.0 * 2.0) = 2.0 fixed-point = 0x0200 [OK]
- Forgetting to shift right after multiplication
- Misinterpreting hex values as decimal
- Incorrect bit shift amount
int16_t a = 0x0100; // 1.0 int16_t b = 0x0200; // 2.0 int16_t c = a * b;
Solution
Step 1: Understand fixed-point multiplication scaling
Multiplying two fixed-point numbers doubles the fractional bits, so the result must be shifted right by the fractional bit count to rescale.Step 2: Analyze given code
The code multiplies a and b but does not shift right by 8 bits, so the scale is incorrect.Final Answer:
Missing right shift to rescale after multiplication -> Option AQuick Check:
Shift right after multiply to fix scale = C [OK]
- Not shifting right after multiplication
- Using float instead of fixed-point on embedded
- Shifting left instead of right
Solution
Step 1: Understand fixed-point multiplication with 12 fractional bits
Multiplying two fixed-point numbers doubles fractional bits (24 bits), so shifting right by 12 bits rescales back to 12 fractional bits.Step 2: Prevent overflow by using wider integer
Multiplying two 16-bit numbers can overflow 16 bits, so use a 32-bit integer to hold the intermediate product safely.Final Answer:
Multiply, then shift right by 12 bits, and store in a 32-bit integer -> Option DQuick Check:
Shift right after multiply and use wider int = B [OK]
- Not using wider integer causing overflow
- Shifting left instead of right after multiply
- Shifting before multiply losing precision
Ready to prove it?
Pass the test and this pattern moves unknown
