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
@@ -963,8 +963,10 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
|
||||
for (int32 RingSample = 0; RingSample < RingSampleCount; ++RingSample)
|
||||
{
|
||||
const float Angle = 2.0f * PI * (float)RingSample / (float)RingSampleCount;
|
||||
const float SampleX = Passage.LowerPoint.X + FMath::Cos(Angle) * RingRadius;
|
||||
const float SampleY = Passage.LowerPoint.Y + FMath::Sin(Angle) * RingRadius;
|
||||
float SinAngle = 0.0f, CosAngle = 0.0f;
|
||||
VoxelMath::DetSinCos(SinAngle, CosAngle, Angle);
|
||||
const float SampleX = Passage.LowerPoint.X + CosAngle * RingRadius;
|
||||
const float SampleY = Passage.LowerPoint.Y + SinAngle * RingRadius;
|
||||
const float Density = World.Generator->GetDensityAt(
|
||||
SampleX,
|
||||
SampleY,
|
||||
@@ -1115,7 +1117,7 @@ bool FVoxelForgePassageLandsInOpenSpaceTest::RunTest(const FString& Parameters)
|
||||
LandingGradient = MaxGradient;
|
||||
WorstLandingFloorGradient = FMath::Max(WorstLandingFloorGradient, MaxGradient);
|
||||
const float NormalZ = 1.0f / FMath::Sqrt(1.0f + MaxGradient * MaxGradient);
|
||||
bFloorPassed = NormalZ + KINDA_SMALL_NUMBER >= FMath::Cos(
|
||||
bFloorPassed = NormalZ + KINDA_SMALL_NUMBER >= VoxelMath::DetCos(
|
||||
FMath::DegreesToRadians(LandingWalkableAngleDegrees));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user