Why FLOPs Are Not Enough for Low-Precision Arithmetic Intensity
On this page↓

1. Background
I remembered that I had not finished CS336. While reviewing the course, I came across this slide, but something felt off. The course defines arithmetic intensity as:
This measures how many abstract floating-point operations can be performed for each byte moved from memory.
For example, consider matrix multiplication , where , , and . The conventional FLOP count is approximately .
Switching from FP32 to FP16 leaves the FLOP count of the same matrix multiplication unchanged. Each element, however, shrinks from 32 bits to 16 bits, roughly halving data movement:
This is the conclusion on the opening slide: lower precision increases arithmetic intensity, making it easier to overcome the memory-bound limit.
But this conclusion depends on an abstraction: an FP16 floating-point operation and an FP32 floating-point operation are both counted as the same FLOP.
If we care about underlying circuit cost, energy, area, and physical computation, this abstraction starts to leak. FP16 addition ≠ FP32 addition; FP16 multiplication ≠ FP32 multiplication. They differ in gate count, transistor switching, capacitive charging and discharging, and the number of units that can operate in parallel.
FLOP count measures operations at the algorithm level, not computation cost at the physical level.
2. The abstraction behind FLOP/Byte
Conventional AI_std implicitly treats floating-point addition, multiplication, or FMA as a common unit of “operation.” For the same GEMM , the FLOP count is therefore in either FP32 or FP16. Only data movement in the denominator changes:
This conclusion is correct at the level of FLOP-count abstraction. It nevertheless ignores one fact: a single FP16 operation is itself cheaper than an FP32 operation.
3. A circuit-level computation model
Let us introduce a rough but informative bit-level compute model.
Let denote the total bit width of a floating-point number, and its effective significand precision:
- FP32: 1 sign bit, 8 exponent bits, 23 fraction bits → , including the hidden leading bit.
- FP16: 1 sign bit, 5 exponent bits, 10 fraction bits → .
Addition
The cost of a -bit adder scales approximately linearly: . Floating-point addition also involves exponent comparison, significand alignment, shifting, normalization, and rounding. The main intuition remains that greater bit width costs more.
Multiplication
A -bit multiplier must generate and reduce many partial products, so its cost scales approximately quadratically: . This is the key point: the circuit cost of low-precision multiplication falls faster than the data width.
FMA
For , use the simplified model:
represents multiplication, and addition or accumulation. This is not an exact hardware energy model, but it captures how circuit complexity scales.
4. A new metric: Bit-Circuit Intensity
Define:
Here, is circuit-level computational work, such as gate-equivalent or partial-product work, and is the number of bits transferred.
Comparing FP16 with FP32:
When all data changes from FP32 to FP16, . The key is therefore .
The conventional FLOP/Byte perspective effectively assumes , giving . At the circuit level, however, is much smaller than , especially for multiplication and FMA.
5. Addition-dominated workloads
For simple addition, approximating cost using bit width ():
For addition, is roughly equal in FP16 and FP32, rather than the conventional .
Approximating cost using significand precision instead ():
Neither estimate reaches .
6. Multiplication-dominated workloads
Multiplication is the more important case. Estimating cost using significand precision:
Multiplying by the factor from halving data transfer:
For multiplication-dominated workloads:
This goes in the opposite direction to the conventional conclusion. The conventional perspective gives ; the circuit-level perspective gives . The difference comes from the fact that an FP16 multiplier occupies roughly a quarter of the area of an FP32 multiplier.
7. FMA- and GEMM-dominated workloads
FMA is more typical in deep learning. Substituting :
Multiplying by the factor from halving data transfer:
For FMA- and GEMM-dominated workloads:
When intensity is defined as circuit-level computation per transferred bit, FP16 decreases intensity rather than increasing it.
8. An explicit derivation for matrix multiplication
For and , let the circuit work per multiply-accumulate be :
FP32:
FP16:
Taking the ratio:
This agrees with Section 7.
9. Mixed precision
Real hardware often uses FP16/BF16 multiplication with FP32 accumulation, rather than pure FP16 FMA:
Compared with the FP32 FMA cost of 600:
If A and B use FP16 and C uses FP32, for a square GEMM ():
Under mixed precision, is approximately in the range .
10. Experimental validation
Environment: RTX 5060 Laptop GPU (Blackwell), CUDA 12.8, and PyTorch cu128. Measured HBM bandwidth: 267.3 GB/s.
Peak throughput
| dtype | Peak TFLOP/s |
|---|---|
| FP32 | 9.71 |
| FP16 | 25.00 |
| BF16 | 35.07 |
FP16 peak throughput is 2.58 times FP32, and BF16 is 3.61 times FP32.
Compute utilization: the decisive metric
ρ tells you how far the workload is from the ridge point. But there is a more direct metric: compute-unit utilization.
directly measures the percentage of hardware peak throughput used by your kernel.
Measuring at different matrix sizes:
| n | AI_std | ||||
|---|---|---|---|---|---|
| 128 | 21 | 8.0% | 3.9% | 2.7% | 0.49 |
| 256 | 43 | 34.1% | 27.8% | 19.0% | 0.81 |
| 512 | 85 | 79.1% | 63.5% | 43.0% | 0.80 |
| 1024 | 171 | 97.4% | 88.8% | 64.7% | 0.91 |
| 2048 | 341 | 99.9% | 105.6% | 91.8% | 1.06 |
| 4096 | 683 | 87.5% | 122.3% | 99.6% | 1.40 |
(Measurements are noisier at n ≥ 2048, where both sides are essentially near saturation. Focus on n = 256, 512, and 1024.)
At the critical size n = 512, FP32 reaches 79% of peak throughput, whereas FP16 reaches only 63%: a gap of 16 percentage points.
On the roofline, at n = 512, AI_FP32 = 85 > ridge_32 = 36, and AI_FP16 = 171 > ridge_16 = 94. Under the conventional model, both should be near saturation. Yet FP16 falls short by 16 percentage points.
Why? Because the ridge moves right farther than AI does. FP32’s AI is 2.4 times its ridge point, while FP16’s is only 1.8 times. A smaller margin makes saturation harder.
This gap applies to any GPU with . For memory-bound kernels, the theoretical lower bound is:
For this GPU, , giving a theoretical lower bound of 0.78. The measured ratio at n = 256 is 0.81, close to that bound.
Conclusion: for any kernel size that has not fully saturated, FP16 compute utilization remains below FP32. Lower precision has not helped you cross the memory wall; it has simply left your compute units less busy.
Across GPU generations
| GPU | Generation | lower bound | |
|---|---|---|---|
| V100 | Volta | 8.0 | 0.25 |
| A100 | Ampere | 16.0 | 0.12 |
| H100 | Hopper | 14.8 | 0.14 |
| RTX 4090 | Ada | 4.0 | 0.50 |
| RTX 5060 | Blackwell | 2.58 | 0.78 (measured: 0.81) |
The stronger a GPU’s Tensor Cores, the lower its FP16 compute utilization. On an A100, FP16 utilization reaches at most 12% of FP32 utilization, not because it is slow, but because it is so fast that memory cannot keep it fed.
11. The relationship to memory-bound workloads
The conventional roofline:
Switching from FP32 to FP16 changes two things simultaneously:
- increases because bytes moved decrease.
- increases even more: FP16 compute units are smaller and denser, and Tensor Cores are available.
The key: grows faster than .
Define :
When , necessarily decreases, and necessarily decreases as well.
12. Summary
Under the conventional FLOP/Byte metric, , because the FLOP count stays constant while data movement halves.
Under the circuit-level metric, the result is entirely different:
| Workload | |
|---|---|
| Addition-dominated | |
| Multiplication-dominated | |
| FMA/GEMM | |
| Mixed Precision GEMM |
The distinction:
- FLOP/Byte perspective: lower precision makes data smaller, so intensity increases.
- Circuit/Bit perspective: lower precision makes computation cheaper, and its cost falls faster, so intensity decreases.
The system-level effect of lower precision is more than simply crossing the memory-bound limit:
- Reduce data movement.
- Reduce the circuit cost of each arithmetic operation.
- Increase hardware peak throughput.
- Make computation cheaper, placing greater importance on data supply, locality, and the memory hierarchy.
Experiment code
roofline_dtype_experiment.ipynb — the complete reproducible RTX 5060 experiment.