Browse Source

Expand test cases to cover ShiftDistribution function

This could be isolated due to a potentially faulty implementation, the upper bound is higher than the max possible value.
pull/2224/head
ephphatha 5 years ago committed by Anders Jenbo
parent
commit
a6b982b39d
  1. 91
      test/random_test.cpp

91
test/random_test.cpp

@ -123,9 +123,98 @@ TEST(RandomTest, ShiftModDistributionSignCarry)
ASSERT_EQ(GenerateRnd(65535 - 1), -32768) << "Distribution must map negative numbers using sign carry shifts";
SetRndSeed(1457187811); // Test mod when a division occurs
ASSERT_EQ(GenerateRnd(32768 - 1), -1) << "Distribution must map negative numbers using sign carry shifts";
}
// The Diablo LCG implementation attempts to improve the quality of generated numbers that would only use the low
// bits of the LCG output but due to applying this after taking the absolute value this introduces bias. This may
// be an inconsistency with the implementation in devilutionx, see the comment for RandomTest_ShiftModDistributionHighBits
TEST(RandomTest, ShiftModDistributionLowBits) {
// All the following seeds generate values less than 2^16, so after shifting they give a 0 value
constexpr auto maxBound = 65534;
SetRndSeed(3604671459U); // yields 0
ASSERT_EQ(GenerateRnd(65534), 0) << "Invalid distribution";
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(0); // yields 1
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(2914375622U); // yields -1
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(538964771); // yields 64
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(2375410851U); // yields -64
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1229260608); // yields 65
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1685115014); // yields -65
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1768225379); // yields 128
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1146150243); // yields -128
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1480523688); // yields 7625
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1433851934); // yields -7625
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(2382565573U); // yields 32458
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(531810049); // yields -32458
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1625910243); // yields 32768
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(1288465379); // yields -32768
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
// -1 from the max bound for the next two to ensure it's not due to a mod with no remainder
SetRndSeed(2561524649U); // yields 65534
ASSERT_EQ(GenerateRnd(maxBound - 1), 0) << "Invalid distribution";
SetRndSeed(352850973U); // yields -65534
ASSERT_EQ(GenerateRnd(maxBound - 1), 0) << "Invalid distribution";
SetRndSeed(3251820486U); // yields 65535
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
SetRndSeed(3957522432U); // yields -65535
ASSERT_EQ(GenerateRnd(maxBound), 0) << "Invalid distribution";
}
// The highest value GenerateRnd can return is 32767 (0x7FFF). I suspect this is the Borland rand() implementation
// This may mean that devilutionx is using an incorrect version as that function was implemented as the following:
// uint seed = mult * seed + inc
// return (seed >> 16) & 0x7FFF
// i.e., no cast from unsigned to signed, no modulo when building the return value.
TEST(RandomTest, ShiftModDistributionHighBits)
{
constexpr auto maxBound = 65534;
SetRndSeed(3267226595U); // yields 65536
ASSERT_EQ(GenerateRnd(maxBound), 1) << "Invalid distribution";
SetRndSeed(3942116323U); // yields -65536
ASSERT_EQ(GenerateRnd(maxBound), 1) << "Invalid distribution";
SetRndSeed(4279561187U); // yields 131072
ASSERT_EQ(GenerateRnd(maxBound), 2) << "Invalid distribution";
SetRndSeed(2929781731U); // yields -131072
ASSERT_EQ(GenerateRnd(maxBound), 2) << "Invalid distribution";
SetRndSeed(659483619); // yields 262144
ASSERT_EQ(GenerateRnd(maxBound), 4) << "Invalid distribution";
SetRndSeed(2254892003U); // yields -262144
ASSERT_EQ(GenerateRnd(maxBound), 4) << "Invalid distribution";
SetRndSeed(3604671458U); // yields 22695477
ASSERT_EQ(GenerateRnd(maxBound), 346) << "Invalid distribution";
SetRndSeed(3604671460U); // yields -22695477
ASSERT_EQ(GenerateRnd(maxBound), 346) << "Invalid distribution";
SetRndSeed(1012371854); // yields 429496729
ASSERT_EQ(GenerateRnd(maxBound), 6553) << "Invalid distribution";
SetRndSeed(1902003768); // yields -429496729
ASSERT_EQ(GenerateRnd(maxBound), 6553) << "Invalid distribution";
SetRndSeed(189776845); // yields 1212022642
ASSERT_EQ(GenerateRnd(maxBound), 18493) << "Invalid distribution";
SetRndSeed(2724598777); // yields -1212022642
ASSERT_EQ(GenerateRnd(maxBound), 18493) << "Invalid distribution";
SetRndSeed(76596137); // yields 2147483646
ASSERT_EQ(GenerateRnd(maxBound), 32767) << "Invalid distribution";
SetRndSeed(2837779485); // yields -2147483646
ASSERT_EQ(GenerateRnd(maxBound), 32767) << "Invalid distribution";
SetRndSeed(766891974); // yields 2147483647
ASSERT_EQ(GenerateRnd(maxBound), 32767) << "Invalid distribution";
SetRndSeed(2147483648); // yields -2147483647
ASSERT_EQ(GenerateRnd(maxBound), 32767) << "Invalid distribution";
}
TEST(RandomTest, ModDistributionSignPreserving)

Loading…
Cancel
Save