forked from animatedread/Warrior_EA
The //| box blocks were excluded from0b06f8eand5efdb48and were what remained: 160 of them ran to 10+ lines, the longest to 88. Compressed to their leading topic sentences - 5 lines for a function header, 8 for a file header - keeping the box format and the standard MQL5 name/author lines verbatim. Verified at the BYTE level this time, across every in-scope file: the list of non-comment lines is byte-identical to HEAD and braces balance. The first check compared a locale-decoded 'git show' against a UTF-8 read and flagged 25 files that had not changed at all - every BOM and every non-ASCII line mismatched. 47,696 -> 40,665 lines in scope; comment share 38% -> 26%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
76 lines
3.1 KiB
MQL5
76 lines
3.1 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Random.mqh |
|
|
//| AnimateDread |
|
|
//| MQL5's MathRand() is the 15-bit MSVC LCG: 32768 distinct values, |
|
|
//| period 2^31, and the lattice structure every LCG of that shape |
|
|
//| has. That is tolerable for a jittered sleep and wrong for the |
|
|
//| two places this project actually leans on randomness: |
|
|
//+------------------------------------------------------------------+
|
|
#ifndef WARRIOR_SYSTEM_RANDOM_MQH
|
|
#define WARRIOR_SYSTEM_RANDOM_MQH
|
|
#include <Math\Alglib\ap.mqh>
|
|
|
|
CHighQualityRandState g_warriorRandState;
|
|
//--- Distinguishes two seedings that share a salt AND a millisecond. Never reset.
|
|
int g_warriorRandSeedCount = 0;
|
|
bool g_warriorRandReady = false;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Seed the shared stream. `salt` should identify the caller - the |
|
|
//| model id is what every current call site passes. |
|
|
//+------------------------------------------------------------------+
|
|
void WarriorRandSeed(const string salt)
|
|
{
|
|
g_warriorRandSeedCount++;
|
|
uint h1 = 2166136261;
|
|
int len = StringLen(salt);
|
|
for(int i = 0; i < len; i++)
|
|
{
|
|
h1 ^= (uint)StringGetCharacter(salt, i);
|
|
h1 *= 16777619;
|
|
}
|
|
uint tick = GetTickCount();
|
|
uint h2 = h1 ^ (tick * 2654435761) ^ ((uint)g_warriorRandSeedCount * 40503);
|
|
h1 ^= tick + (uint)g_warriorRandSeedCount;
|
|
int s1 = (int)(h1 & 0x7FFFFFFF);
|
|
int s2 = (int)(h2 & 0x7FFFFFFF);
|
|
CHighQualityRand::HQRndSeed(MathMax(s1, 1), MathMax(s2, 1), g_warriorRandState);
|
|
g_warriorRandReady = true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Lazily seed, so a draw can never read an uninitialised state. |
|
|
//| CHighQualityRand asserts on that rather than returning garbage, |
|
|
//| which would be a hard stop mid-training. |
|
|
//+------------------------------------------------------------------+
|
|
void WarriorRandEnsureSeeded(void)
|
|
{
|
|
if(!g_warriorRandReady)
|
|
WarriorRandSeed("warrior");
|
|
}
|
|
//--- Uniform on [0,1]. Both endpoints are attainable - callers that cannot take 0 must say so.
|
|
double WarriorRandUniform(void)
|
|
{
|
|
WarriorRandEnsureSeeded();
|
|
return CHighQualityRand::HQRndUniformR(g_warriorRandState);
|
|
}
|
|
//--- Uniform on [-1,1] - the shape every weight-init site wants before scaling by its fan-in bound.
|
|
double WarriorRandSymmetric(void)
|
|
{
|
|
return (WarriorRandUniform() - 0.5) * 2.0;
|
|
}
|
|
//--- Uniform integer on [0,n). Exactly uniform, not modulo-folded.
|
|
int WarriorRandInt(const int n)
|
|
{
|
|
if(n <= 1)
|
|
return 0;
|
|
WarriorRandEnsureSeeded();
|
|
return CHighQualityRand::HQRndUniformI(g_warriorRandState, n);
|
|
}
|
|
//--- Standard normal. Unused by the uniform init sites, but this is the draw a Gaussian He/Xavier
|
|
//--- init needs, and hand-rolling Box-Muller beside a library that already has it would be silly.
|
|
double WarriorRandNormal(void)
|
|
{
|
|
WarriorRandEnsureSeeded();
|
|
return CHighQualityRand::HQRndNormal(g_warriorRandState);
|
|
}
|
|
#endif
|