19 Fixed-Point Arithmetic
More
Depth: Practitioner
Progress saves as you read. Mark sections complete as you go; your progress appears in the sidebar.
19.1 Start With a Floating-Point Cost You Can Avoid
This section: Start With a Floating-Point Cost You Can Avoid — Picture a battery sensor that stays awake to calculate a value its small processor could handle with scaled integers.
Save Compute Time Without Changing the Answer
Picture a battery sensor that stays awake to calculate a value its small processor could handle with scaled integers. A faster result is useful only if its error remains safe.
Firmware means the software stored on the device. Duty cycle means the share of time a device spends active instead of asleep. Fixed-point work may reduce that active share.
Run the same input set through the old and new calculation, including limits and negative values. Record scale, range, rounding, overflow, error, run time, energy, and failures.
This runway does not prove that fixed-point arithmetic is always better. The deeper sections explain Q-formats, range, resolution, intermediate width, saturation, rounding, testing, and energy trade-offs.
On a small MCU, a floating-point calculation may wake helper code, burn cycles, and stretch active time. Fixed-point arithmetic is the trade: choose a Q-format that keeps enough range and resolution while using cheaper integer work.
Start with the value range, scale it explicitly, protect intermediate width, and validate the error before counting the energy saving.
19.3 Fixed-Point Arithmetic
This section: Fixed-Point Arithmetic — Fixed-point arithmetic is a way to run fractional math through integer operations.
Fixed-point arithmetic is a way to run fractional math through integer operations. Instead of storing a value as a floating-point number, firmware stores an integer and agrees that the binary point sits at a fixed location.
This is useful in constrained IoT firmware when floating-point work is slow, large, unavailable, or too energy-heavy for the measured duty cycle. It is not automatically better. The design must prove range, precision, overflow behavior, and whole-device energy impact.
19.4 Learning Objectives
This section: Learning Objectives
By the end of this chapter, you will be able to:
- Explain how Q-format fixed-point values represent scaled real numbers.
- Select integer and fractional bits from measured range and required precision.
- Convert between real values, scaled integers, and engineering units.
- Implement addition, multiplication, rounding, and saturation safely.
- Identify overflow, wraparound, quantization error, and mixed-format bugs.
- Build validation evidence that compares fixed-point output with a reference result.
19.5 Q-Format Model
This section: Q-Format Model — In the signed Qn.m convention used here, one bit is the sign, n bits are the integer magnitude, and m bits are fractional; the total width is 1+n+m bits.
In the signed Qn.m convention used here, one bit is the sign, n bits are the integer magnitude, and m bits are fractional; the total width is 1+n+m bits. The stored integer maps to the real value:
The smallest step is:
Do not reduce q-format model to a single headline metric. The visual in Figure 19.1 brings 2^n-1 and sign into the same frame, ready for the evidence comparison that follows.
On the figure at Figure 19.1, read 2^n-1 as the point that adds a distinct review condition; sign then adds a distinct review condition. The separate 2^n-2 label adds a distinct review condition, preventing the first two stages from being accepted on their own. The complete reading is that no-panel Q-format diagram showing sign and integer bits, fractional bits, scale factor, resolution, and stored integer value. This distinction carries forward into q-format model.
19.6 Range
The integer side must cover every expected value plus margin for abnormal inputs and intermediate states.
19.7 Resolution
The fractional side must be fine enough that quantization error stays within the product requirement.
19.8 Intermediate Width
Multiplication and accumulation usually need a wider temporary type before shifting back to the target format.
19.9 Saturation Policy
Define what happens when a result exceeds the format: clamp, flag, fallback, or reject the input.
19.10 Choosing A Format
This section: Choosing A Format — Choose a format from evidence, not from a favorite convention.
Choose a format from evidence, not from a favorite convention.
19.11 Conversion Workflow
This section: Conversion Workflow — The safest workflow is to preserve a reference implementation while you convert one numeric path at a time.
The safest workflow is to preserve a reference implementation while you convert one numeric path at a time.
- Capture representative input ranges and edge cases.
- Define acceptable output error.
- Choose the Q-format and intermediate widths.
- Convert inputs with explicit rounding.
- Implement operations with rescaling and saturation.
- Compare fixed-point outputs against the reference.
- Remeasure full-cycle energy and timing on the target.
19.12 Core Operations
This section: Core Operations
19.13 Conversion
This section: Conversion
To convert a real value to fixed point:
To convert back:
// Example: signed Q7.8 stored in int16_t.
#define Q_FRAC 8
#define Q_SCALE (1 << Q_FRAC)
static inline int16_t q_from_milli(int32_t milli_units) {
// milli_units is value * 1000; round ties away from zero and saturate.
int64_t scaled = (int64_t)milli_units * Q_SCALE;
int64_t rounded = (scaled >= 0 ? scaled + 500 : scaled - 500) / 1000;
if (rounded > INT16_MAX) return INT16_MAX;
if (rounded < INT16_MIN) return INT16_MIN;
return (int16_t)rounded;
}
static inline int32_t q_to_milli(int16_t q_value) {
return ((int32_t)q_value * 1000) / Q_SCALE;
}
19.14 Addition
This section: Addition — Addition is direct only when both operands use the same scale.
Addition is direct only when both operands use the same scale.
int16_t q_add_sat(int16_t a, int16_t b) {
int32_t sum = (int32_t)a + (int32_t)b;
if (sum > INT16_MAX) return INT16_MAX;
if (sum < INT16_MIN) return INT16_MIN;
return (int16_t)sum;
}
19.15 Multiplication
This section: Multiplication — Multiplication doubles the fractional scale.
Multiplication doubles the fractional scale. Use a wider temporary, round ties away from zero, then saturate.
int16_t q_mul_q7_8(int16_t a, int16_t b) {
int64_t product = (int64_t)a * b;
int64_t magnitude = product < 0 ? -product : product;
int64_t rounded = (magnitude + 128) / 256;
if (product < 0) rounded = -rounded;
if (rounded > INT16_MAX) rounded = INT16_MAX;
if (rounded < INT16_MIN) rounded = INT16_MIN;
return (int16_t)rounded;
}
19.16 Division
This section: Division — Division is often replaced with multiplication by a precomputed reciprocal.
Division is often replaced with multiplication by a precomputed reciprocal. If division remains, widen before shifting so fractional information is not lost too early.
int16_t q_div_q7_8(int16_t numerator, int16_t denominator) {
if (denominator == 0) {
return numerator >= 0 ? INT16_MAX : INT16_MIN;
}
int32_t widened = (int32_t)numerator * 256;
int32_t result = widened / denominator;
if (result > INT16_MAX) return INT16_MAX;
if (result < INT16_MIN) return INT16_MIN;
return (int16_t)result;
}
19.17 Overflow And Saturation
This section: Overflow And Saturation — Wraparound can turn a large positive value into a negative one.
Wraparound can turn a large positive value into a negative one. For measurements, filters, and control paths, saturation plus a fault flag is often safer.
Clamp Outputs Clamp to the representable limit when the next consumer expects a bounded physical value.
Flag Faults Record that saturation happened so the system can reduce trust, retry, or enter a safe mode.
Test Boundaries Include maximum, minimum, zero, negative, and near-overflow values in regression tests.
Keep Units Visible Name variables by unit or scale so mixed-format arithmetic is visible in review.
19.18 Validation Gates
This section: Validation Gates — Fixed-point arithmetic changes numerical behavior.
Fixed-point arithmetic changes numerical behavior. Accept it only when the evidence record proves the change is safe for the product.
The chapter now moves from describing validation gates to checking it. The diagram at Figure 19.2 is the checkpoint because it puts Measured range plus margin beside Golden vectors, where an unsupported assumption becomes visible.
Figure 19.2 anchors its argument at Measured range plus margin, where the diagram marks the acceptance limit. Follow the presented relationship to Golden vectors (adds a distinct review condition) and finish with Reference outputs compare (adds a distinct review condition). In other words, no-panel fixed-point validation gates: range survey, golden vectors, overflow tests, error budget, target timing, and full-cycle energy evidence. This closes the visual check required for validation gates.
19.19 Review Checklist
This section: Review Checklist
Before accepting fixed-point firmware:
- The numeric range is measured or bounded.
- The Q-format, units, and scale are documented beside the code.
- Conversion uses explicit rounding rather than accidental truncation.
- Multiplication and accumulation use a safe intermediate width.
- Saturation or fault behavior is defined for out-of-range results.
- Golden vectors compare fixed-point output with a reference result.
- Boundary tests cover min, max, zero, negative, and near-overflow values.
- Full-cycle timing and energy are remeasured on the target build.
19.20 Knowledge Check
This section: Knowledge Check
19.21 Knowledge Check: Choosing A Q-Format
This section: Knowledge Check: Choosing A Q-Format
19.22 Knowledge Check: Multiplication
This section: Knowledge Check: Multiplication
19.23 Match Fixed-Point Item To Purpose
This section: Match Fixed-Point Item To Purpose
19.24 Order The Fixed-Point Conversion Workflow
This section: Order The Fixed-Point Conversion Workflow
19.25 Label The Fixed-Point Design Record
This section: Label The Fixed-Point Design Record
19.26 On A Core Without An FPU, Every Float Is A Subroutine
This section: On A Core Without An FPU, Every Float Is A Subroutine — Fixed-point arithmetic is usually taught as a way to save code space or gain speed, but on a battery device its biggest payoff is energy.
Fixed-point arithmetic is usually taught as a way to save code space or gain speed, but on a battery device its biggest payoff is energy. Many low-power microcontroller cores - the Cortex-M0, M0+, and M3, for example - have no hardware floating-point unit. On those cores, every floating-point operation is executed by a software library routine that can take tens of processor cycles, while the same work in fixed-point uses ordinary integer instructions that take only a few.
Cycles are the link to energy. At a fixed clock and active current, more cycles means a longer active window, which means more energy per operation and a later return to sleep. So on an FPU-less core, choosing fixed-point over floating-point does not just run faster; it shortens how long the processor stays awake, which is where the battery is spent.
For example, compare 10000 numeric multiplies in a burst on a 16 MHz core drawing 1.5 mA while active. If software float averages 50 cycles per multiply, the burst takes 10000 x 50 / 16e6 = 31.25 ms and consumes about 1.5 mA x 0.03125 s = 0.0469 mA-s. If fixed-point averages 3 cycles, the same burst takes 1.875 ms and about 0.0028 mA-s. The operation count did not change; the active window did.
If that burst runs once per second, the difference is about 0.044 mA-s every second, or 0.044 mA of average current. Over a day that is roughly 1.06 mAh of charge, before counting any radio or sensor load.
Intuition only: without a hardware FPU, a float multiply is a function call that burns many cycles. Fixed-point turns it back into a one-cycle integer multiply, and the cycle savings become active-time and energy savings.
19.27 Why The Cost Differs
This section: Why The Cost Differs
No FPU
M0, M0+, and M3 cores have no floating-point hardware, so floats run as software routines.
Soft-float cost
A software float operation can take tens of cycles; division costs even more.
Fixed-point cost
Q-format math uses integer multiply and shift, often a single-cycle multiply on the M0+.
Cycles to energy
Fewer cycles at a fixed clock means less active time and less energy per result.
19.28 Overview Knowledge Check
This section: Overview Knowledge Check
19.29 Cycles Become Active Time Becomes Energy
This section: Cycles Become Active Time Becomes Energy — Estimate the compute energy as cycles / clock x I_active.
Estimate the compute energy as cycles / clock x I_active. On an FPU-less core the cycle count is where floating-point loses, and the loss multiplies across a hot loop.
To decide whether cycles become active time becomes energy is defensible, first locate Inputs, outputs, limits and Error budget in the figure at Figure 19.3. They expose the two conditions that the surrounding argument must keep together.
Find Inputs, outputs, limits on Figure 19.3; it establishes the starting condition. Now contrast Error budget, which adds a distinct review condition, with Reference tolerance, which adds a distinct review condition. That contrast is the visual’s teaching load: Fixed-point conversion workflow from range survey and error budget through Q-format choice, safe implementation, boundary tests, and energy remeasurement. The chapter can now use cycles become active time becomes energy without dropping the conditions shown here.
19.30 Worked Example: A 1000-Tap Filter On An FPU-less Core
This section: Worked Example: A 1000-Tap Filter On An FPU-less Core — A filter runs 1000 multiply-accumulate operations per sample on a 16 MHz Cortex-M0+ drawing about 1.5 mA when active.
A filter runs 1000 multiply-accumulate operations per sample on a 16 MHz Cortex-M0+ drawing about 1.5 mA when active. Take a software single-precision multiply-accumulate at roughly 50 cycles and a Q15 fixed-point multiply-accumulate at roughly 3 cycles.
- Cycles per sample: float 1000 x 50 = 50000 cycles; fixed 1000 x 3 = 3000 cycles - about 17x fewer.
- Active time per sample: float 50000 / 16e6 = 3.125 ms; fixed 3000 / 16e6 = 0.1875 ms.
- At 100 samples per second: float keeps the core computing 312.5 ms of every second (31%); fixed keeps it computing only 18.75 ms (under 2%). Average compute current is about 0.47 mA for float versus 0.028 mA for fixed - roughly 17x, which after adding a small sleep floor still stretches battery life by more than tenfold.
The float version does not just take longer; it holds the processor out of sleep nearly a third of the time, which is what wrecks the energy budget on an FPU-less core.
That active-duty result can be turned into a battery-review number. At 1.5 mA active current, the float compute path averages about 1.5 mA x 0.3125 = 0.469 mA before other device loads. The fixed path averages about 1.5 mA x 0.01875 = 0.028 mA. Over one day of continuous sampling, compute alone is about 11.3 mAh for float versus 0.67 mAh for fixed.
19.31 Compute Energy Ledger
This section: Compute Energy Ledger
19.32 Practitioner Knowledge Check
This section: Practitioner Knowledge Check
19.33 The Trap Is Core-Dependent
This section: The Trap Is Core-Dependent — The energy case for fixed-point depends entirely on the core.
The energy case for fixed-point depends entirely on the core. On a Cortex-M4F or M7 with a single-precision FPU, a float multiply is nearly as fast as an integer one, so fixed-point's energy edge for single-precision work largely disappears and its accuracy pitfalls may not be worth it. The decision must follow the hardware, not a habit.
But an FPU core hides a sharp trap: it accelerates only single-precision floats. A stray double-precision operation is still emulated in software, at a cost like the FPU-less case. This happens silently in C when a literal lacks the f suffix, so y = x * 0.5 promotes x to double and computes in software, whereas y = x * 0.5f stays in the hardware FPU. The same trap appears when a program calls sin instead of sinf, or assigns to a double variable. A design that expected the FPU to keep compute cheap can quietly fall back to slow software doubles, inflating active time and energy exactly as if the FPU were not there. The practitioner habit is to confirm the core, keep hot math single-precision with f-suffixed literals and single-precision library calls, and reserve fixed-point for FPU-less parts or for squeezing the last cycles.
The audit evidence is concrete. In a Cortex-M4F build, hot-path disassembly should show single-precision FPU instructions such as vmul.f32 or calls to single-precision helpers, not double-precision software routines. A map file that pulls in helpers such as __aeabi_dmul, __aeabi_dadd, or conversions between double and float is a warning that part of the numeric path escaped the hardware FPU. That evidence decides whether fixed-point is solving a real energy problem or merely adding scale-management risk.
19.34 Matching The Math To The Core
This section: Matching The Math To The Core
FPU-less core
Fixed-point wins clearly; every float is emulated. Prefer Q-format for hot loops.
Single-precision FPU
Hardware float is cheap; fixed-point's energy edge shrinks for single-precision work.
Accidental double
A missing f suffix or a double call falls back to slow software emulation on an SP-only FPU.
Verify, do not assume
Check the map file or disassembly to confirm hot math used the FPU, not the soft-float library.
19.35 Under-the-Hood Knowledge Check
This section: Under-the-Hood Knowledge Check
19.36 Summary
This section: Summary
Fixed-point arithmetic is useful when numerical requirements are clear:
- Represent real values as scaled integers.
- Select Q-format from range and precision evidence.
- Use safe intermediate widths for multiply and accumulate operations.
- Prefer explicit rounding and saturation over accidental truncation and wraparound.
- Compare against a reference with golden vectors and boundary tests.
- Remeasure timing and full-cycle energy before claiming an optimisation.
Common Pitfalls
This section: Common Pitfalls
A format with excellent resolution can still fail when a real input exceeds its integer range.
The final result may fit, but the intermediate product can overflow unless the temporary type is wide enough.
Wraparound can flip sign or hide a fault. Use saturation, flags, and boundary tests for physical values.
Fixed-point work must be remeasured across the device duty cycle. Faster math is not enough if sleep, radio, or memory behavior changes badly.
19.37 What’s Next
This section: What’s Next
19.38 Review The Optimisation Loop
Hardware and Software Optimisation explains how to choose the right optimisation lever from evidence.
19.39 Tune Firmware
Software Optimization Techniques covers profiling, compiler settings, memory layout, and sleep-aware firmware.
19.40 Compare Hardware Paths
Hardware Optimization Strategies covers acceleration and processor selection when software changes are not enough.
19.41 Measure The Result
Energy Measurement and Profiling shows how to collect the before/after current trace.
19.42 Key Takeaway
This section: Key Takeaway — Fixed-point optimization can save memory, cycles, and energy, but only when range, scaling, rounding, overflow, and accuracy are tested against the real signal and control requirements.
Fixed-point optimization can save memory, cycles, and energy, but only when range, scaling, rounding, overflow, and accuracy are tested against the real signal and control requirements.
Open printable teacher run sheet
Find help
3 reviewed answers.
Where should I start in a module?
Open the module page from the sidebar to see its chapters in order. Use the module map to return to a topic you need.
Modules and pathsReviewed
What can I try when a project does not work?
Check the symptom, then work through the diagnostic steps. Keep the error message and the smallest example that reproduces it.
When you are stuckReviewed
How do interactive examples work?
Use the interactive guide to check how examples and simulations work before changing your project.
Interactive examples guideReviewed
