From 84ac79d7bd86448f3281e960fd4df41adda9860b Mon Sep 17 00:00:00 2001 From: Eric-Butcher Date: Sun, 29 Jun 2025 11:53:40 -0400 Subject: [PATCH 1/2] Added test cases for inclusive ranges when generating integers --- tests/test_LinearCongruentialGenerator.cpp | 52 +++++++++++++++++++- tests/test_MersenneTwister.cpp | 52 +++++++++++++++++++- tests/test_XORShift.cpp | 56 +++++++++++++++++++++- 3 files changed, 156 insertions(+), 4 deletions(-) diff --git a/tests/test_LinearCongruentialGenerator.cpp b/tests/test_LinearCongruentialGenerator.cpp index bd5c6ca..7911e1d 100644 --- a/tests/test_LinearCongruentialGenerator.cpp +++ b/tests/test_LinearCongruentialGenerator.cpp @@ -125,7 +125,7 @@ TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueEquidistributed) } -TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiveRange){ +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiveRangePositive){ LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); const int32_t min = 1; const int32_t max = 6; @@ -146,6 +146,56 @@ TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiv } } + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiveRangeNegative){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const int32_t min = -6; + const int32_t max = -1; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = lcg.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiveRangeNegativeAndPositive){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const int32_t min = -10; + const int32_t max = 10; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = lcg.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + ASSERT_TRUE(found_min); ASSERT_TRUE(found_max); } \ No newline at end of file diff --git a/tests/test_MersenneTwister.cpp b/tests/test_MersenneTwister.cpp index 5cbe701..4f5b69b 100644 --- a/tests/test_MersenneTwister.cpp +++ b/tests/test_MersenneTwister.cpp @@ -111,7 +111,7 @@ TEST(TestMersenneTwister, GenerateIntegerRandomValueEquidistributed){ } -TEST(TestMersenneTwister, GenerateIntegerRandomValueProducesInclusiveRange){ +TEST(TestMersenneTwister, GenerateIntegerRandomValueProducesInclusiveRangePositive){ MersenneTwister mt = MersenneTwister(); const int32_t min = 1; const int32_t max = 6; @@ -132,6 +132,56 @@ TEST(TestMersenneTwister, GenerateIntegerRandomValueProducesInclusiveRange){ } } + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + +TEST(TestMersenneTwister, GenerateIntegerRandomValueProducesInclusiveRangeNegative){ + MersenneTwister mt = MersenneTwister(); + const int32_t min = -6; + const int32_t max = -1; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = mt.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + +TEST(TestMersenneTwister, GenerateIntegerRandomValueProducesInclusiveRangeNegativeAndPositive){ + MersenneTwister mt = MersenneTwister(); + const int32_t min = -10; + const int32_t max = 10; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = mt.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + ASSERT_TRUE(found_min); ASSERT_TRUE(found_max); } \ No newline at end of file diff --git a/tests/test_XORShift.cpp b/tests/test_XORShift.cpp index 0f0c662..56488c4 100644 --- a/tests/test_XORShift.cpp +++ b/tests/test_XORShift.cpp @@ -123,7 +123,7 @@ TEST(TestXORShift, GenerateIntegerRandomValueEquidistributed){ ASSERT_NEAR(expected_value, average, margin_of_error); } -TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRange){ +TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRangePositive){ XORShift xor_shift = XORShift(); const int32_t min = 1; const int32_t max = 6; @@ -146,4 +146,56 @@ TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRange){ ASSERT_TRUE(found_min); ASSERT_TRUE(found_max); -} \ No newline at end of file +} + +TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRangeNegative){ + XORShift xor_shift = XORShift(); + const int32_t min = -6; + const int32_t max = -1; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = xor_shift.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + +TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRangeNegativeAndPositive){ + XORShift xor_shift = XORShift(); + const int32_t min = -10; + const int32_t max = 10; + const int max_iterations = 1000; + bool found_min = false; + bool found_max = false; + + for (int i = 0; i < max_iterations; ++i) { + int64_t value = xor_shift.generateIntegerRandomValue(min, max); + if (value == min) { + found_min = true; + } + if (value == max) { + found_max = true; + } + if (found_min && found_max) { + break; // No need to continue if both values are found + } + } + + ASSERT_TRUE(found_min); + ASSERT_TRUE(found_max); +} + + From 3340c0fe4035af4dee6ac3321bcaa2aee81afaa7 Mon Sep 17 00:00:00 2001 From: Eric-Butcher Date: Sun, 29 Jun 2025 14:32:17 -0400 Subject: [PATCH 2/2] Fixed the problem with the inclusive range when engative numbers are used in generateIntegerRandomValue. --- src/prngs/prng.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/prngs/prng.cpp b/src/prngs/prng.cpp index f6623dd..6628e72 100644 --- a/src/prngs/prng.cpp +++ b/src/prngs/prng.cpp @@ -47,8 +47,9 @@ double PseudoRandomNumberGenerator::generateFloatingPointRandomValue(float min, int64_t PseudoRandomNumberGenerator::generateIntegerRandomValue(int32_t min, int32_t max) { double random_val = generateUnitNormalRandomValue(); - double random_val_magnitude = random_val * (max - min + 1); - int64_t scaled_value = static_cast(min + random_val_magnitude); + int64_t inclusive_range = max - min + 1; + double random_val_magnitude = random_val * static_cast(inclusive_range); + int64_t scaled_value = static_cast(random_val_magnitude) + min; return scaled_value; }