#include "RandomNumberGenerator.hpp" #include #include #include // is used for testing the time in the 3rd test case TEST_CASE("random_number_generator_basic", "[]") { // This test was written to check basic functions like whether different // numbers are generated. SECTION("check_whether_different_16", "[]") { // creates a new RNG object RandomNumberGenerator* xor_shift = new RandomNumberGenerator(); // creates two pseudo random 16 bit numbers u_int16_t test_1 = xor_shift->gen_rdm_16_bit(); u_int16_t test_2 = xor_shift->gen_rdm_16_bit(); // printes these numbers out std::cout << "1st generated 16 bit int: " << test_1 << std::endl; std::cout << "2nd generated 16 bit int: " << test_2 << std::endl; // checks whether these numbers are different // test1 == test2 wouldn't means that the test isn't random. // This section just exists to see whether the algorithm basically works // and generates numbers. CHECK(test_1 != test_2); } // The same test like above but for the 32 bit algorithm: SECTION("CheckWhetherDifferent32", "[]") { RandomNumberGenerator xor_shift; u_int32_t test_1 = xor_shift.gen_rdm_32_bit(); u_int32_t test_2 = xor_shift.gen_rdm_32_bit(); std::cout << "1st generated 32 bit int: " << test_1 << std::endl; std::cout << "2nd generated 32 bit int: " << test_2 << std::endl; CHECK(test_1 != test_2); } // The same test like above but for the 64 bit algorithm: SECTION("CheckWhetherDifferent64", "[]") { RandomNumberGenerator xor_shift; u_int64_t test_1 = xor_shift.gen_rdm_64_bit(); u_int64_t test_2 = xor_shift.gen_rdm_64_bit(); std::cout << "1st generated 64 bit int: " << test_1 << std::endl; std::cout << "2nd generated 64 bit int: " << test_2 << std::endl; CHECK(test_1 != test_2); // empty line for better layout in testlog std::cout << std::endl; } // This test checks the type of the return value. // This particular section is for 16 bit SECTION("CheckSize16", "[]") { // Creates a RNG and generates a number like above RandomNumberGenerator xor_shift; u_int16_t test_value = xor_shift.gen_rdm_16_bit(); std::cout << "values that are generated for checking the size: " << std::endl; std::cout << "generated value: " << test_value << std::endl; // checks wheter the size of the return value is 16 bit or 2 byte CHECK(sizeof(test_value) == 2); } // The same for 32 bit SECTION("CheckSize32", "[]") { RandomNumberGenerator xor_shift; u_int32_t test_value = xor_shift.gen_rdm_32_bit(); std::cout << "generated value (32 bit): " << test_value << std::endl; // checks wheter the size of the return value is 32 bit or 4 byte CHECK(sizeof(test_value) == 4); } // The same for 64 bit SECTION("CheckSize64", "[]") { RandomNumberGenerator xor_shift; u_int64_t test_value = xor_shift.gen_rdm_64_bit(); std::cout << "generated value (64 bit): " << test_value << std::endl; // checks wheter the size of the return value is 64 bit or 8 byte CHECK(sizeof(test_value) == 8); std::cout << std::endl; } // Checks whether different numbers are generated when using different RNGs SECTION( "Check whether different when using different RNG objects for 16 bit", "[]") { // creating two objects RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; // generating two values of 16 bit std::cout << "16 bit seed 1: " << xor_shift_1._seed_x16 << std::endl; std::cout << "16 bit seed 2: " << xor_shift_2._seed_x16 << std::endl; u_int16_t test_1_16_bit = xor_shift_1.gen_rdm_16_bit(); u_int16_t test_2_16_bit = xor_shift_2.gen_rdm_16_bit(); CHECK(test_1_16_bit != test_2_16_bit); } // the same for 32 bit again: SECTION( "Check whether different when using different RNG objects for 32 bit", "[]") { RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; std::cout << "32 bit seed 1: " << xor_shift_1._seed_x32 << std::endl; std::cout << "32 bit seed 2: " << xor_shift_2._seed_x32 << std::endl; u_int32_t test_1_32_bit = xor_shift_1.gen_rdm_32_bit(); u_int32_t test_2_32_bit = xor_shift_2.gen_rdm_32_bit(); CHECK(test_1_32_bit != test_2_32_bit); } // the same for 64 bit again: SECTION( "Check whether different when using different RNG objects for 64 bit", "[]") { RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; std::cout << "64 bit seed 1: " << xor_shift_1._seed_x64 << std::endl; std::cout << "64 bit seed 2: " << xor_shift_2._seed_x64 << std::endl; u_int64_t test_1_64_bit = xor_shift_1.gen_rdm_64_bit(); u_int64_t test_2_64_bit = xor_shift_2.gen_rdm_64_bit(); CHECK(test_1_64_bit != test_2_64_bit); std::cout << std::endl; } // This test checks whether two RNGs generate the same number after the seed // is set to the same number SECTION("Check whether the same numbers are generated with the same seed " "for 16 bit", "[]") { RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; // set the seed to the same value in both RNGs xor_shift_1._seed_x16 = 30000; xor_shift_2._seed_x16 = 30000; std::cout << "16 bit seed for RNG 1: " << xor_shift_1._seed_x16 << std::endl; std::cout << "16 bit seed for RNG 2: " << xor_shift_2._seed_x16 << std::endl; u_int16_t test_1_16_bit = xor_shift_1.gen_rdm_16_bit(); u_int16_t test_2_16_bit = xor_shift_2.gen_rdm_16_bit(); std::cout << "number generated from RNG 1: " << xor_shift_1._seed_x16 << std::endl; std::cout << "number generated from RNG 2: " << xor_shift_2._seed_x16 << std::endl; // check whether the results are the same too CHECK(test_1_16_bit == test_2_16_bit); std::cout << std::endl; } // the same test for 32 bit SECTION("Check whether the same numbers are generated with the same seed " "for 32 bit", "[]") { RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; // set the seed to the same value in both RNGs xor_shift_1._seed_x32 = 30000000; xor_shift_2._seed_x32 = 30000000; std::cout << "32 bit seed for RNG 1: " << xor_shift_1._seed_x32 << std::endl; std::cout << "32 bit seed for RNG 2: " << xor_shift_2._seed_x32 << std::endl; u_int32_t test_1_32_bit = xor_shift_1.gen_rdm_32_bit(); u_int32_t test_2_32_bit = xor_shift_2.gen_rdm_32_bit(); std::cout << "number generated from RNG 1: " << xor_shift_1._seed_x32 << std::endl; std::cout << "number generated from RNG 2: " << xor_shift_2._seed_x32 << std::endl; // check whether the results are the same too CHECK(test_1_32_bit == test_2_32_bit); std::cout << std::endl; } // the same test for 64 bit SECTION("Check whether the same numbers are generated with the same seed " "for 64 bit", "[]") { RandomNumberGenerator xor_shift_1; RandomNumberGenerator xor_shift_2; // set the seed to the same value in both RNGs xor_shift_1._seed_x64 = 30000000000; xor_shift_2._seed_x64 = 30000000000; std::cout << "64 bit seed for RNG 1: " << xor_shift_1._seed_x64 << std::endl; std::cout << "64 bit seed for RNG 2: " << xor_shift_2._seed_x64 << std::endl; u_int64_t test_1_64_bit = xor_shift_1.gen_rdm_64_bit(); u_int64_t test_2_64_bit = xor_shift_2.gen_rdm_64_bit(); std::cout << "number generated from RNG 1: " << xor_shift_1._seed_x64 << std::endl; std::cout << "number generated from RNG 2: " << xor_shift_2._seed_x64 << std::endl; // check whether the results are the same too CHECK(test_1_64_bit == test_2_64_bit); std::cout << std::endl; } SECTION("Check whether generated numbers are really in the interval", "[]") { RandomNumberGenerator xor_shift; u_int16_t test_value; int lower_limit = 1024; int upper_limit = 49151; bool no_number_has_been_outside_the_interval = true; // inside the for loop an if statement checks for 1,000,000 generated // numbers whether they are really in the interval for (int i = 0; i < 10000000; i++) { test_value = xor_shift.gen_rdm_16_bit_in_interval(lower_limit, upper_limit); if (test_value < lower_limit || test_value > upper_limit) { no_number_has_been_outside_the_interval = false; } } std::cout << "No generated number has been outside the interval? (1 " "means true) --> " << no_number_has_been_outside_the_interval << std::endl; std::cout << std::endl; CHECK(no_number_has_been_outside_the_interval == true); } } TEST_CASE("RandomNumberGeneratorStatistics", "[]") { // The result of the chi square test shows how uniform the generated numbers // are distributed // A big chi square means that the actual frequencies vary widely from the // theoretical frequencies. SECTION("ChiSquare16", "[]") { RandomNumberGenerator xor_shift; // 65536 - 1 = 2 ^ 16 different numbers can be generated int r = 65536 - 1; // 1,000,000 numbers are generated int n = 1000000; u_int16_t t; // this array counts how often each number from 0 to r is returned as a // result int f[r] = {}; for (int i = 0; i < r; i++) { f[i] = 0; } for (int i = 1; i < n; i++) { t = xor_shift.gen_rdm_16_bit_in_interval(1024, 49151); f[t]++; } double chisquare = 0.0; for (int i = 0; i < r; i++) { // chi square is calculated chisquare = chisquare + ((f[i] - n / r) * (f[i] - n / r) / (n / r)); } std::cout << "+++ chi square test for gen_rdm_16_bit_in_interval() +++" << std::endl; std::cout << "chi square is: " << chisquare << std::endl; double k = sqrt(chisquare / (n + chisquare)); std::cout << "k is: " << k << std::endl; // k is in [0; k_max] with k_max ≈ 1 // Calculating k_norm wouldn't make sense. // 0 means that every number is generated equally frequent // 1 means not random at all // A bad result could be improved by returning _seed_x16 instead of // _seed_x16 % 48128 + 1024 (valid port number) in // RandomNumberGenerator.cpp. CHECK(k < 1.0); std::cout << std::endl; } SECTION("ChiSquare16", "[]") { RandomNumberGenerator xor_shift; // 65526 - 1 = 2 ^ 16 different numbers can be generated int r = 65536 - 1; // 1,000,000 numbers are generated int n = 1000000; u_int16_t t; // this array counts how often each number from 0 to r is returned as a // result int f[r] = {}; for (int i = 0; i < r; i++) { f[i] = 0; } for (int i = 1; i < n; i++) { t = xor_shift.gen_rdm_16_bit(); f[t]++; } double chisquare = 0.0; for (int i = 0; i < r; i++) { // chi square is calculated chisquare = chisquare + ((f[i] - n / r) * (f[i] - n / r) / (n / r)); } std::cout << "+++ chi square test for gen_rdm_16_bit() +++" << std::endl; std::cout << "chi square is: " << chisquare << std::endl; double k = sqrt(chisquare / (n + chisquare)); std::cout << "k is: " << k << std::endl; CHECK(k < 1.0); std::cout << std::endl; } // the following test fails due to an segmentation violation signal // 32 bit seems to be to big /*SECTION("ChiSquare32", "[]") { RandomNumberGenerator xor_shift; u_int32_t r = 4294967296 - 1; u_int64_t n = 10000000000; u_int32_t t; int f[r] = {}; for (u_int64_t i = 0; i < r; i++) { f[i] = 0; } for (u_int64_t i = 1; i < n; i++) { t = xor_shift.gen_rdm_32_bit(); f[t]++; } double chisquare = 0.0; for (int i = 0; i < r; i++) { chisquare = chisquare + ((f[i] - n / r) * (f[i] - n / r) / (n / r)); } std::cout << "chi square is: " << chisquare << std::endl; double k = sqrt(chisquare / (n + chisquare)); std::cout << "k is: " << k << std::endl; // k is in [0; k_max] with k_max ≈ 1 // 0 means independence // 1 means not random at all CHECK(k < 1.0); }*/ } TEST_CASE("RandomNumberGeneratorTime", "[]") { // The following section is calculating the time for generating n // 16 bit numbers with a single RNG object SECTION("TestTime16", "[]") { // the following two lines initialize and start the timer double time1 = 0.0, tstart; tstart = clock(); // creating a RNG object RandomNumberGenerator xor_shift; // amount of numbers generated // can be changed if neccessary, but it you will get a segmentation // violation error if it's to big long n = 10000000; // variable to store generated number uint16_t test_value; // generating those numbers for (long i = 0; i < n; i++) { test_value = xor_shift.gen_rdm_16_bit(); } // stops the timer and calculates the difference between start and end time1 += clock() - tstart; // prints out the time std::cout << "time needed to generate " << n << " 16 bit numbers: " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 10.0); } // This test calculates the time needed to generate a certain amount of 16 // bit ints with rand() allowowing a comparison with xorShift SECTION("TestTime16Rand", "[]") { double time1 = 0.0, tstart; tstart = clock(); long n = 10000000; uint16_t test_value; for (long i = 0; i < n; i++) { test_value = rand(); } time1 += clock() - tstart; std::cout << "time needed to generate " << n << " 16 bit numbers with rand(): " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 10.0); } // the same test for 32 bit numbers SECTION("TestTime32", "[]") { double time1 = 0.0, tstart; tstart = clock(); RandomNumberGenerator xor_shift; long n = 10000000; uint32_t test_value; for (long i = 0; i < n; i++) { test_value = xor_shift.gen_rdm_32_bit(); } time1 += clock() - tstart; std::cout << "time needed to generate " << n << " 32 bit numbers: " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 1.0); } // true 32 bit numbers with shifting and rand() for comparison to the // section above SECTION("TestTime32Rand", "[]") { double time1 = 0.0, tstart; tstart = clock(); long n = 10000000; uint32_t test_value; for (long i = 0; i < n; i++) { test_value = (uint16_t)rand(); test_value |= (uint16_t)rand() << 16; } time1 += clock() - tstart; std::cout << "time needed to generate " << n << " 32 bit numbers with rand() and shifting: " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 1.0); } // the same test for 64 bit numbers SECTION("TestTime64", "[]") { double time1 = 0.0, tstart; tstart = clock(); RandomNumberGenerator xor_shift; long n = 10000000; uint64_t test_value; for (long i = 0; i < n; i++) { test_value = xor_shift.gen_rdm_64_bit(); } time1 += clock() - tstart; std::cout << "time needed to generate " << n << " 64 bit numbers: " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 1.0); } // true 64 bit numbers with shifting and rand() for comparison to the // section above SECTION("TestTime64Rand", "[]") { double time1 = 0.0, tstart; tstart = clock(); long n = 10000000; uint64_t test_value = 0; for (long i = 0; i < n; i++) { // the following lines have been copied from // Treatment::create_cookie_secret() u_int64_t value1 = (uint16_t)rand(); value1 = (value1 << 48); test_value |= value1; u_int64_t value2 = (uint16_t)rand(); value2 = (value2 << 32); test_value |= value2; u_int64_t value3 = (uint16_t)rand(); test_value |= value3; } time1 += clock() - tstart; std::cout << "time needed to generate " << n << " 64 bit numbers with rand() and shifting: " << time1 / CLOCKS_PER_SEC << " s" << std::endl; CHECK(time1 / CLOCKS_PER_SEC < 1.0); } }