<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/determinism-box2d-z84y8zj4g" -->

---
title: Determinism :: Box2D | daily.dev
description: Erin Catto explains how Box2D v3 achieves three levels of determinism: algorithmic (no random numbers), multithreaded (using per-thread bit arrays merged with...
canonical: https://daily.dev/posts/determinism-box2d-z84y8zj4g
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Determinism :: Box2D | daily.dev
og:description: Erin Catto explains how Box2D v3 achieves three levels of determinism: algorithmic (no random numbers), multithreaded (using per-thread bit arrays merged with...
og:url: https://daily.dev/posts/determinism-box2d-z84y8zj4g
og:image: https://api.daily.dev/og/posts/Z84y8Zj4g.png
og:image:alt: Determinism :: Box2D
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Determinism :: Box2D

**[
        
            Box2D 
        
    ](https://daily.dev/sources/box2d)** · 9 min read · 0 upvotes · 0 comments

## Summary

Erin Catto explains how Box2D v3 achieves three levels of determinism: algorithmic (no random numbers), multithreaded (using per-thread bit arrays merged with OR operations instead of atomics/mutexes to keep contact ordering consistent), and cross-platform (avoiding fast-math and fused multiply-add, and implementing custom sinf/cosf/atan2f to sidestep compiler and CPU rounding differences). A CI-based test called Falling Hinges verifies determinism across MSVC, Clang, GCC, x64, and ARM by checking that sleep step counts and transform hashes match. Roll-back determinism, needed for multiplayer client-side prediction, is not yet supported due to Box2D's heavy internal state, but is planned as a future experimental feature.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://box2d.org/posts/2024/08/determinism>

## Questions this post answers

### How does Box2D v3 maintain deterministic contact ordering when using multiple threads?

Box2D avoids atomics and mutexes for ordering by having each worker thread fill a local bit array representing contacts it found, then merging all thread-local bit arrays on the main thread with a bitwise OR operation. This produces a deterministic global sequence of set bits, so the order bodies and shapes were created in the world determines contact order regardless of which thread finished first.

_Multithreaded engine developers chasing similar synchronization bugs can find deep dives like this on daily.dev._

### Do I need fixed-point math to get cross-platform determinism in a physics engine?

No, fixed-point math is not required for cross-platform determinism once you avoid a few specific floating-point traps. Box2D achieves deterministic results across x64 and ARM, and across MSVC, GCC, and Clang, by disabling fast-math, turning off fused multiply-add (using -ffp-contract=off on Clang/GCC), and implementing custom versions of atan2f since it produced different results across platforms while sinf and cosf did not.

_Developers weighing fixed-point versus floating-point strategies can track these trade-offs on daily.dev._

### Why does fused multiply-add (FMA) break determinism in floating-point code?

FMA instructions round only once when computing a multiply-then-add expression, improving precision and performance slightly, but they are not available on all CPUs and different compilers choose differently when to emit them. This leads to inconsistent rounding results across platforms, so for cross-platform determinism FMA must be explicitly disabled, for example with the -ffp-contract=off compiler flag on Clang and GCC.

_Engineers debugging cross-platform floating-point mismatches can follow issues like this on daily.dev._

## Similar posts on daily.dev

- [Announcing Box3D :: Box2D](https://daily.dev/posts/announcing-box3d-box2d-mu8ehdvki) · Lobsters · 0 upvotes · 0 comments
- [A Physics Engine with Incremental Rollback • Easel](https://daily.dev/posts/a-physics-engine-with-incremental-rollback-easel-smqrkuh1s) · Hacker News · 1 upvotes · 0 comments

---

[View this post on daily.dev](https://daily.dev/posts/determinism-box2d-z84y8zj4g)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Determinism :: Box2D","url":"https://daily.dev/posts/determinism-box2d-z84y8zj4g","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/determinism-box2d-z84y8zj4g"},"datePublished":"2026-08-23T12:16:55.757Z","dateModified":"2026-08-23T12:18:35.983Z","description":"Erin Catto explains how Box2D v3 achieves three levels of determinism: algorithmic (no random numbers), multithreaded (using per-thread bit arrays merged with...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e04395b6674cb0948f8827a71d318efa?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e04395b6674cb0948f8827a71d318efa?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"\n        \n            Box2D \n        \n    ","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"\n        \n            Box2D \n        \n    ","logo":"https://media.daily.dev/image/upload/s--fmoS1AL5--/f_auto,q_auto/v1787487406/logos/box2d?_a=BAMAMicg0","url":"https://daily.dev/sources/box2d"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/determinism-box2d-z84y8zj4g","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"","timeRequired":"PT9M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"\n        \n            Box2D \n        \n    ","item":"https://daily.dev/sources/box2d"},{"@type":"ListItem","position":3,"name":"Determinism :: Box2D"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/determinism-box2d-z84y8zj4g#faq","mainEntity":[{"@type":"Question","name":"How does Box2D v3 maintain deterministic contact ordering when using multiple threads?","acceptedAnswer":{"@type":"Answer","text":"Box2D avoids atomics and mutexes for ordering by having each worker thread fill a local bit array representing contacts it found, then merging all thread-local bit arrays on the main thread with a bitwise OR operation. This produces a deterministic global sequence of set bits, so the order bodies and shapes were created in the world determines contact order regardless of which thread finished first. Multithreaded engine developers chasing similar synchronization bugs can find deep dives like this on daily.dev."}},{"@type":"Question","name":"Do I need fixed-point math to get cross-platform determinism in a physics engine?","acceptedAnswer":{"@type":"Answer","text":"No, fixed-point math is not required for cross-platform determinism once you avoid a few specific floating-point traps. Box2D achieves deterministic results across x64 and ARM, and across MSVC, GCC, and Clang, by disabling fast-math, turning off fused multiply-add (using -ffp-contract=off on Clang/GCC), and implementing custom versions of atan2f since it produced different results across platforms while sinf and cosf did not. Developers weighing fixed-point versus floating-point strategies can track these trade-offs on daily.dev."}},{"@type":"Question","name":"Why does fused multiply-add (FMA) break determinism in floating-point code?","acceptedAnswer":{"@type":"Answer","text":"FMA instructions round only once when computing a multiply-then-add expression, improving precision and performance slightly, but they are not available on all CPUs and different compilers choose differently when to emit them. This leads to inconsistent rounding results across platforms, so for cross-platform determinism FMA must be explicitly disabled, for example with the -ffp-contract=off compiler flag on Clang and GCC. Engineers debugging cross-platform floating-point mismatches can follow issues like this on daily.dev."}}]}
```

