fix(determinism): own sin/cos on the world path -- same world on every CPU, 3.5% faster
On Win64, FMath::Sin/Cos resolve to CRT sinf/cosf (GenericPlatformMath.h:521/530; no platform override), and the UCRT picks FMA3 or non-FMA3 implementations at startup by CPU. /fp:precise closed only the compiler half, so the same build and seed could build a slightly different world on two Windows PCs, and on Linux. - VoxelMath::DetSin/DetCos/DetSinCos (VoxelTypes.h): fixed double-precision period reduction to a quarter period, then fixed float minimax polynomials; no CRT, FMath or CPU-dependent intrinsic. Measured max error vs sinf 5.96e-8 over the used range (|arg| <= 6.19). - Every world-deciding FMath::Sin/Cos replaced (generator, op stacks, cave morphology, strate manager, content placement, strate measure); none remain in runtime code. - Pinned test VoxelForge.Determinism.DetSinCos (golden bit patterns + error bound). - Diagnostic start-up switch -voxel.CrtFma3=0 (Windows) forces the CRT's non-FMA3 path. - Parse-once console switches now initialise in StartupModule on the game thread; workers only read them (was an unsynchronised first parse inside GetDensityAt). - Corrected the CRC comment that claimed a CRC32 cannot give a false positive. Proof (Codex round; orchestrator re-checked): - Before the fix, FMA3 on vs off was identical on this Ryzen 7 5800X3D: the hole exists but was not observed in this world. After the fix, the canonical exports are byte-identical with FMA3 on and off. - The world changed once, as expected. New canonical export SHA-256 CBB8AE18...906F (geometry B9EF84AC; was B3E5F4C3...377); worms region 9242C093 (was 311CA42C), walk OBJ 20CCF7BD.... Triangle counts unchanged in every tile. Order-independent nearest-vertex distance, worms region: max 8.7 micrometres (the reported "11.4 m" was a line-order artefact of a line-by-line OBJ diff); export region max 3e-5 m. - Capability exact: player-fit 20,830, walk-reachable 10,909, connected. TilePostReachProof, sealed-proof, cross-platform and strate-crossing tests pass. - Performance, headless game path, S/M/S/M vs the committed-tip DLL: static worker 27.41 s vs 28.44 s (-3.6%), moving 59.59 s vs 61.74 s (-3.5%); LOD0 p50/p95 not worse. From Sol's code review (DESIGN-SOL-2026-09-15-CODE.md, section 4.1), branch sol/deterministic-math. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
1 parent
cda082fa10
commit
10fd0b6e77
16 files changed
+393
-85
No files matched your search
@@ -7504,7 +7504,7 @@ namespace
|
||||
if (!(DistFromSurface < LineRange)) { return; }
|
||||
|
||||
const float LinePhase = WorldZ * (2.0f * PI) / LP.LayerLineSpacing;
|
||||
float LineValue = FMath::Sin(LinePhase);
|
||||
float LineValue = VoxelMath::DetSin(LinePhase);
|
||||
|
||||
LineValue = FMath::Max(LineValue, 0.0f);
|
||||
LineValue = LineValue * LineValue * LineValue; // affûtage cubique
|
||||
@@ -7606,7 +7606,7 @@ namespace
|
||||
if (!(DistFromSurface < RibRange)) { return; }
|
||||
|
||||
const float RibPhase = WorldZ * (2.0f * PI) / LP.RibbingSpacing + PI * 0.5f;
|
||||
float RibValue = FMath::Sin(RibPhase);
|
||||
float RibValue = VoxelMath::DetSin(RibPhase);
|
||||
|
||||
RibValue = FMath::Max(RibValue, 0.0f);
|
||||
RibValue = RibValue * RibValue; // profil de bosse arrondi
|
||||
|
||||
Reference in new issue
Block a user