Engineering Insights

The Butterfly Effect in Your FPU: Why Parallel Math is Chaos

Jonathan Corners | January 2026

Taming the nondeterministic nature of parallel floating point. In regulated sectors like HFT and Defense, 'approximate' results are a liability. We explore the engineering challenges of achieving 100% reproducibility.

The Problem in Three Lines

// Parallel reduction: same inputs, different outputs
Thread A: (a + b) + c = 0.30000000000000004
Thread B: a + (b + c) = 0.3

// This isn't a bug. It's IEEE 754 working as designed.

In most applications, this doesn’t matter. If a pixel in your video game is #FEFEFE instead of #FFFFFF, nobody calls a lawyer. But in regulated sectors like high-frequency trading, defense systems, or medical devices, “close enough” is a liability that can invalidate audits, fail certification, and create legal exposure.

Why Floating Point Arithmetic Isn’t Associative

Floating point numbers have finite precision. They are like trying to write down $\pi$ on a sticky note. You eventually run out of space and have to round off. When you add two numbers, the result is rounded to fit. The order in which you perform additions affects which intermediate results get rounded, producing different final bits.

a = 1e-16
b = 1.0
c = -1.0

# Mathematically equivalent. Computationally different.
(a + b) + c  # = 1.1102230246251565e-16
a + (b + c)  # = 1e-16

Think of it like packing a suitcase. If you put the big shoes in first, the socks fit in the gaps. If you put the socks in first, the shoes might not fit the same way. The contents are the same, but the final package looks different.

This is fine for graphics rendering. It is catastrophic when:

  • Regulators require you to reproduce a calculation from 6 months ago.
  • Two nodes in a distributed system must agree on a result.
  • Legal discovery demands you prove what value was computed.
  • Safety certification requires deterministic behavior.

Parallelism Makes It Worse

Sequential code has predictable ordering. It is a single-file line at the cafeteria. Parallel code is a mosh pit.

// GPU parallel reduction: 1024 threads summing values
__shared__ float sdata[1024];

// Which threads finish first? Depends on:
// - Warp scheduling (hardware-dependent)
// - Memory latency (runtime-dependent)
// - Thread block assignment (launch-dependent)

// The reduction tree shape changes run-to-run
// Therefore: the rounding sequence changes
// Therefore: the result changes

A parallel sum of 10,000 floats can produce thousands of distinct bit patterns across runs. All “correct” within floating point semantics. All useless for reproducibility.

The Regulatory Reality

High-Frequency Trading

MiFID II and SEC Rule 613 require firms to reconstruct trades. When your P&L calculation uses parallel floating point, “reconstruction” means hoping the GPU schedules threads the same way it did months ago. It won’t.

Defense & Aerospace

DO-178C (airborne systems) and DO-254 (hardware) require deterministic behavior for safety-critical calculations. Nondeterministic parallel reduction fails certification.

Medical Devices

FDA 21 CFR Part 11 requires reproducible calculations for audit trails. A diagnostic algorithm that produces different results on re-run is a regulatory violation.

Autonomous Vehicles

ISO 26262 (functional safety) requires predictable behavior. When your perception pipeline produces different object distances on identical sensor data, you can’t certify the vehicle.

Engineering Approaches

1. Fixed Reduction Order

Force the same operation sequence regardless of thread timing. You are essentially telling the mosh pit to form a conga line.

// Deterministic parallel reduction
__device__ float deterministic_reduce(float* data, int n) {
    // Always reduce in the same tree pattern
    for (int stride = 1; stride < n; stride *= 2) {
        int idx = threadIdx.x * stride * 2;
        if (idx + stride < n) {
            data[idx] += data[idx + stride];
        }
        __syncthreads();  // Force ordering
    }
    return data[0];
}

Cost: Serialization points destroy parallelism. Expect 2-5x slowdown.

2. Kahan Summation

Compensated summation tracks rounding error, reducing order sensitivity. It is like carrying a small notebook to write down the change you lost in the couch cushions.

float kahan_sum(float* values, int n) {
    float sum = 0.0f;
    float c = 0.0f;  // Running compensation

    for (int i = 0; i < n; i++) {
        float y = values[i] - c;
        float t = sum + y;
        c = (t - sum) - y;  // Recover lost bits
        sum = t;
    }
    return sum;
}

Cost: 4x the operations per element. Reduces but doesn’t eliminate order dependence.

3. Fixed-Point Arithmetic

Integers are associative. Convert to fixed-point, compute, convert back.

// Price in cents, not dollars
int64_t price_cents = 12345;  // $123.45

// All integer operations are deterministic
int64_t total = price_cents * quantity;

// Convert only at boundaries
double display_price = total / 100.0;

Cost: Reduced dynamic range. Risk of overflow. Awkward API boundaries.

4. Deterministic Libraries

NVIDIA’s cuBLAS and cuDNN offer deterministic modes:

// cuBLAS deterministic mode
cublasSetMathMode(handle, CUBLAS_MATH_DISALLOW_REDUCED_PRECISION_REDUCTION);

// cuDNN deterministic mode
cudnnSetConvolutionMathType(conv_desc, CUDNN_DEFAULT_MATH);
cudnnSetDeterministic(handle, true);

Cost: Significant performance penalty (often 2-10x). Not all operations supported. Version-dependent behavior.

5. Reproducible PRNG Seeding

For stochastic algorithms, determinism requires reproducible random streams.

// Bad: Time-based seed
srand(time(NULL));

// Good: Content-based seed
uint64_t seed = hash(input_data, input_size);
std::mt19937_64 rng(seed);

Cost: Must propagate seeds through all parallel branches consistently.

The Performance-Reproducibility Tradeoff

Approach Determinism Performance Hit Complexity
Fixed reduction order 100% 2-5x Low
Kahan summation ~99%* 2-4x Low
Fixed-point 100% 1.5-3x High
Deterministic libraries 100%** 2-10x Low
Custom accumulator 100% 3-8x High

*Kahan reduces but doesn’t eliminate order sensitivity **When available and correctly configured

Practical Recommendations

For New Systems

  1. Define determinism requirements upfront. Retrofitting is expensive.
  2. Use fixed-point for financial calculations. Always.
  3. Isolate nondeterministic components. Keep the audit trail deterministic even if ML inference isn’t.
  4. Version your math libraries. cuBLAS 11.x and 12.x produce different “deterministic” results.
  5. Test reproducibility explicitly. Run the same calculation 1000 times, assert bit equality.

For Existing Systems

  1. Identify critical paths. Not everything needs determinism.
  2. Add determinism flags. Let operators choose speed vs. reproducibility.
  3. Log intermediate results. When you can’t reproduce, at least you can audit.
  4. Consider replay architectures. Store inputs, replay deterministically offline.

A Note on “Good Enough”

Some applications need bit-exact reproducibility. Others need bounded deviation. Know which you need.

// Bit-exact: cryptographic, financial, legal
assert(result_a == result_b);

// Bounded: scientific, engineering
assert(fabs(result_a - result_b) < epsilon);

// Statistical: ML training, simulation
assert(distribution_a  distribution_b);  // KS test

Demanding bit-exact when bounded suffices wastes performance. Accepting bounded when bit-exact is required creates liability.

Conclusion

Parallel floating point is inherently nondeterministic due to IEEE 754 rounding and operation reordering. In regulated sectors, this creates audit, certification, and legal risks that must be engineered around.

The solutions exist but carry performance costs. The key is understanding your actual requirements: not every calculation needs determinism, but the ones that do need it absolutely.

Define your boundaries early. Test reproducibility continuously. And never assume two “correct” floating point results are the same.


Further Reading

  • Higham, N. (2002). Accuracy and Stability of Numerical Algorithms
  • IEEE 754-2019 Standard for Floating-Point Arithmetic
  • NVIDIA. Floating Point and IEEE 754 Compliance for NVIDIA GPUs
  • Demmel, J. & Nguyen, H. D. (2013). “Fast Reproducible Floating-Point Summation”

Author

Jonathan Corners - Founder, Voxell. I build GPU-native infrastructure for real-time AI systems.

If you're working on latency + consistency problems, I'd like to hear about it.

Contact 24h reply • NDA ok • No IP needed

Ready to see this in practice?

Get hands-on with Voxell Coherence.

Request Access