diff --git a/src/prngs/prng.cpp b/src/prngs/prng.cpp index 507e27e..d6fb66a 100644 --- a/src/prngs/prng.cpp +++ b/src/prngs/prng.cpp @@ -47,7 +47,7 @@ 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); + double random_val_magnitude = random_val * (max - min + 1); int64_t scaled_value = static_cast(min + random_val_magnitude); return scaled_value; } \ No newline at end of file diff --git a/tests/test_LinearCongruentialGenerator.cpp b/tests/test_LinearCongruentialGenerator.cpp index cb5cb95..bd5c6ca 100644 --- a/tests/test_LinearCongruentialGenerator.cpp +++ b/tests/test_LinearCongruentialGenerator.cpp @@ -3,6 +3,7 @@ #include "linear_congruential_generator.hpp" #include #include +#include // Test that the lcg constructors do not fail TEST(TestLinearCongruentialGenerator, BlankConstructor) { @@ -61,3 +62,90 @@ TEST(TestLinearCongruentialGenerator, GenerateUnitNormalRandomValueEquidistribut const double confidence_interval = 0.01; EXPECT_NEAR(average, expected_average, confidence_interval); } + + +TEST(TestLinearCongruentialGenerator, GenerateFloatingPointRandomValueInRange){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const float min = -25.678f; + const float max = 3242.342f; + const int num_iterations = 1000; + for (int i = 0; i < num_iterations; ++i){ + double value = lcg.generateFloatingPointRandomValue(min, max); + ASSERT_GE(value, min); + ASSERT_LE(value, max); + } +} + +TEST(TestLinearCongruentialGenerator, GenerateFloatingPointRandomValueEquidistributed){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const double min = -300.0; + const double max = 700.0; + const int num_iterations = 10000; + double sum = 0.0; + double variance_sum = 0.0; + double expected_value = (min + max) / 2.0; + for (int i = 0; i < num_iterations; ++i){ + double value = lcg.generateFloatingPointRandomValue(min, max); + sum += value; + variance_sum += (value - expected_value) * (value - expected_value); + } + double average = sum / num_iterations; + double variance = variance_sum / num_iterations; + double standard_deviation = std::sqrt(variance); + double three_sigma = 3 * standard_deviation; + ASSERT_NEAR(expected_value, average, three_sigma);; + +} + +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueInRange){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const int32_t min = -70; + const int32_t max = 141; + const int num_iterations = 1000; + for (int i = 0; i < num_iterations; ++i){ + int64_t value = lcg.generateIntegerRandomValue(min, max); + ASSERT_GE(value, min); + ASSERT_LE(value, max); + } +} + +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueEquidistributed){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const int32_t min = 1; + const int32_t max = 6; + const int num_iterations = 10000; + double sum = 0; + double expected_value = (min + max) / 2.0; + for (int i = 0; i < num_iterations; ++i){ + sum += static_cast(lcg.generateIntegerRandomValue(min, max)); + } + double average = sum / num_iterations; + double margin_of_error = 0.02 * expected_value; + ASSERT_NEAR(expected_value, average, margin_of_error); +} + + +TEST(TestLinearCongruentialGenerator, GenerateIntegerRandomValueProducesInclusiveRange){ + LinearCongruentialGenerator lcg = LinearCongruentialGenerator(); + const int32_t min = 1; + const int32_t max = 6; + 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_XORShift.cpp b/tests/test_XORShift.cpp index 69b5a6e..0f0c662 100644 --- a/tests/test_XORShift.cpp +++ b/tests/test_XORShift.cpp @@ -3,6 +3,7 @@ #include "xorshift.hpp" #include #include +#include // Test that the lcg constructors do not fail TEST(TestXORShift, BlankConstructor) { @@ -34,7 +35,7 @@ TEST(TestXORShift, SeedAndConstantsConstructor) { TEST(TestXORShift, GenerateUnitNormalRandomValueHasCorrectRange) { XORShift xor_shift = XORShift(); - const int enough_iterations_to_be_confident = 10000; + const int enough_iterations_to_be_confident = 1000; for (int i = 0; i < enough_iterations_to_be_confident; ++i) { const double value = xor_shift.generateUnitNormalRandomValue(); EXPECT_GE(value, 0.0); @@ -59,4 +60,90 @@ TEST(TestXORShift, GenerateUnitNormalRandomValueEquidistributed) { const double average = sum / enough_iterations_to_be_confident; const double confidence_interval = 0.01; EXPECT_NEAR(average, expected_average, confidence_interval); +} + + +TEST(TestXORShift, GenerateFloatingPointRandomValueInRange){ + XORShift xor_shift = XORShift(); + const float min = -25.678f; + const float max = 3242.342f; + const int num_iterations = 1000; + for (int i = 0; i < num_iterations; ++i){ + double value = xor_shift.generateFloatingPointRandomValue(min, max); + ASSERT_GE(value, min); + ASSERT_LE(value, max); + } +} + +TEST(TestXORShift, GenerateFloatingPointRandomValueEquidistributed){ + XORShift xor_shift = XORShift(); + const double min = -300.0; + const double max = 700.0; + const int num_iterations = 10000; + double sum = 0.0; + double variance_sum = 0.0; + double expected_value = (min + max) / 2.0; + for (int i = 0; i < num_iterations; ++i){ + double value = xor_shift.generateFloatingPointRandomValue(min, max); + sum += value; + variance_sum += (value - expected_value) * (value - expected_value); + } + double average = sum / num_iterations; + double variance = variance_sum / num_iterations; + double standard_deviation = std::sqrt(variance); + double three_sigma = 3 * standard_deviation; + ASSERT_NEAR(expected_value, average, three_sigma); + +} + +TEST(TestXORShift, GenerateIntegerRandomValueInRange){ + XORShift xor_shift = XORShift(); + const int32_t min = -70; + const int32_t max = 141; + const int num_iterations = 1000; + for (int i = 0; i < num_iterations; ++i){ + int64_t value = xor_shift.generateIntegerRandomValue(min, max); + ASSERT_GE(value, min); + ASSERT_LE(value, max); + } +} + +TEST(TestXORShift, GenerateIntegerRandomValueEquidistributed){ + XORShift xor_shift = XORShift(); + const int32_t min = 1; + const int32_t max = 6; + const int num_iterations = 10000; + double sum = 0.0; + double expected_value = (min + max) / 2.0; + for (int i = 0; i < num_iterations; ++i){ + sum += static_cast(xor_shift.generateIntegerRandomValue(min, max)); + } + double average = sum / num_iterations; + double margin_of_error = 0.02 * expected_value; + ASSERT_NEAR(expected_value, average, margin_of_error); +} + +TEST(TestXORShift, GenerateIntegerRandomValueProducesInclusiveRange){ + XORShift xor_shift = XORShift(); + const int32_t min = 1; + const int32_t max = 6; + 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); } \ No newline at end of file