1

I have this algorithm for shuffling, I am trying to replace the Rand with Mersenne as an enhancement since Mersenne is more efficient and produces much randomness compared to rand according to what I've searched. However, when comparing it side by side, I ran it for 5 times each and total the repetitions of each 5 cases, I get more repetition when using Mersenne than in Rand. Why is that? I'm new to programming, your help is appreciated. Thank you!

This is my code for using Mersenne

#include <iostream>
#include <vector>
#include <random>
#include <chrono>

struct Element {
    int value;
    std::string attribute1;
    std::string attribute2;
    std::string attribute3;
    std::string attribute4;
    std::string attribute5;
    int count;
};

bool haveSameAttributes(const Element& elem1, const Element& elem2) {
    return (elem1.attribute1 == elem2.attribute1 &&
            elem1.attribute2 == elem2.attribute2 &&
            elem1.attribute3 == elem2.attribute3 &&
            elem1.attribute4 == elem2.attribute4 &&
            elem1.attribute5 == elem2.attribute5);
}

void enhancedShuffle(std::vector<Element>& rndnum, std::mt19937& gen) {

    int n = rndnum.size();
    int n1 = n;
    int j = n - 1;
    int attempts = 0;
    const int max_attempts = n1; // Maximum number of attempts allowed

    // Reset the count for all elements to 0
    for (Element& elem : rndnum) {
        elem.count = 0; // Assuming count is a member variable of Element
    }

    for (int i = 0; i < n; ++i) {
        // Using Mersenne Twister PRNG
        std::uniform_int_distribution<> dist(0, n1 - 1);
        int x = dist(gen);
        rndnum[x].count++;

        if (i > 0) {
            // Check Element's Attributes (5) & Max Attempt to n1
            if ((rndnum[x].value == rndnum[j + 1].value || haveSameAttributes(rndnum[x], rndnum[j + 1])) && attempts < max_attempts) {
                int z = dist(gen);
                ++attempts;

                // Compare Selection Count of Elements
                if (rndnum[x].count > rndnum[i - 1].count && attempts < max_attempts) {
                    // Using Mersenne Twister PRNG
                    x = dist(gen);
                    ++attempts;
                    rndnum[x].count++;
                }

                if ((x + z) >= j) {
                    x = (x + z) - j;
                } else {
                    x = x + z;
                }

            }
        }

        std::swap(rndnum[x], rndnum[j]);
        --n1;
        --j;
    }
}

// For counting the repetitions throughout the shuffled list
int countConsecutiveRepetitions(const std::vector<Element>& rndnum) {
    int consecutiveRepetitions = 0;

    for (size_t i = 1; i < rndnum.size(); ++i) {
        if (haveSameAttributes(rndnum[i], rndnum[i - 1])) {
            ++consecutiveRepetitions;
        }
    }
    return consecutiveRepetitions;
}

std::vector<int> countConsecutiveRepetitionsPerAttribute(const std::vector<Element>& rndnum) {
    int consecutiveRepetitions1 = 0;
    int consecutiveRepetitions2 = 0;
    int consecutiveRepetitions3 = 0;
    int consecutiveRepetitions4 = 0;
    int consecutiveRepetitions5 = 0;

    for (size_t i = 1; i < rndnum.size(); ++i) {
        if (rndnum[i].attribute1 == rndnum[i - 1].attribute1) {
            ++consecutiveRepetitions1;
        }
        if (rndnum[i].attribute2 == rndnum[i - 1].attribute2) {
            ++consecutiveRepetitions2;
        }
        if (rndnum[i].attribute3 == rndnum[i - 1].attribute3) {
            ++consecutiveRepetitions3;
        }
        if (rndnum[i].attribute4 == rndnum[i - 1].attribute4) {
            ++consecutiveRepetitions4;
        }
        if (rndnum[i].attribute5 == rndnum[i - 1].attribute5) {
            ++consecutiveRepetitions5;
        }
    }
    int totalConsecutiveAttributes = consecutiveRepetitions1 + consecutiveRepetitions2 + consecutiveRepetitions3 + consecutiveRepetitions4 + consecutiveRepetitions5;
    return {consecutiveRepetitions1, consecutiveRepetitions2, consecutiveRepetitions3, consecutiveRepetitions4, consecutiveRepetitions5, totalConsecutiveAttributes};
}

int main() {
    const int desiredSize = 50;
    const int numIterations = 1000;
    std::vector<Element> baseList = {
        {1, "Dragon", "Large", "Long", "Shoes", "Green"},
        {2, "Dragon", "Small", "Average", "Boots", "Green"},
        {3, "Dragon", "Small", "Short", "Slippers", "Red"},
        {4, "Dragon", "Medium", "Average", "Shoes", "White"},
        {5, "Dragon", "Large", "Long", "Boots", "Red"},
    };

    int totalConsecutiveRepetitions = 0;
    std::vector<int> totalConsecutiveRepetitionsPerAttribute(5, 0);

    auto seed = static_cast<unsigned>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
    std::mt19937 gen(seed);

    for (int iteration = 0; iteration < numIterations; ++iteration) {
        std::vector<Element> rndnum;

        // Repeat the base list to achieve the desired size
        while (rndnum.size() < desiredSize) {
            rndnum.insert(rndnum.end(), baseList.begin(), baseList.end());
        }

        // Trim the excess elements
        rndnum.resize(desiredSize);

        enhancedShuffle(rndnum, gen);

        // Display each element with its attributes (Optional)
//        for (const auto& element : rndnum) {
//            std::cout << "Value: " << element.value
//                      << ", Attribute1: " << element.attribute1
//                      << ", Attribute2: " << element.attribute2
//                      << ", Attribute3: " << element.attribute3
//                      << ", Attribute4: " << element.attribute4
//                      << ", Attribute5: " << element.attribute5
//                      << ", Count: " << element.count << std::endl;
//        }

        int consecutiveRepetitions = countConsecutiveRepetitions(rndnum);
        totalConsecutiveRepetitions += consecutiveRepetitions;

        std::vector<int> consecutiveRepetitionsPerAttribute = countConsecutiveRepetitionsPerAttribute(rndnum);
        for (int i = 0; i < 5; ++i) {
            totalConsecutiveRepetitionsPerAttribute[i] += consecutiveRepetitionsPerAttribute[i];
        }

        std::cout << "\nConsecutive repetitions in iteration " << iteration + 1 << ": " << consecutiveRepetitions << std::endl;
        std::cout << "---------------------------------------------\n";

    }

    int totalAttributeCounts = 0;
    for (int count : totalConsecutiveRepetitionsPerAttribute) {
        totalAttributeCounts += count;
    }

    std::cout << "\nTotal Consecutive repetitions across all iterations: " <<  totalConsecutiveRepetitions << std::endl;

    return 0;
}

RESULTS: MERSENNE

  • CASE 1: 2317
  • CASE 2: 2222
  • CASE 3: 2325
  • CASE 4: 2331
  • CASE 5: 2314

Now this is my code for using Rand

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>

struct Element {
    int value;
    std::string attribute1;
    std::string attribute2;
    std::string attribute3;
    std::string attribute4;
    std::string attribute5;
    int count;
};

bool haveSameAttributes(const Element& elem1, const Element& elem2) {
    return (elem1.attribute1 == elem2.attribute1 &&
            elem1.attribute2 == elem2.attribute2 &&
            elem1.attribute3 == elem2.attribute3 &&
            elem1.attribute4 == elem2.attribute4 &&
            elem1.attribute5 == elem2.attribute5);
}

void enhancedShuffle(std::vector<Element>& rndnum) {

    int n = rndnum.size();
    int n1 = n;
    int j = n - 1;
    int attempts = 0;
    const int max_attempts = n1; // Maximum number of attempts allowed

    // Reset the count for all elements to 0
    for (Element& elem : rndnum) {
        elem.count = 0; // Assuming count is a member variable of Element
    }

    for (int i = 0; i < n; ++i) {
        // Using Mersenne Twister PRNG
        int x = rand() % n1;
        rndnum[x].count++;

        if (i > 0) {
            // Check Element's Attributes (5) & Max Attempt to n1
            if ((rndnum[x].value == rndnum[j + 1].value || haveSameAttributes(rndnum[x], rndnum[j + 1])) && attempts < max_attempts) {
                int z = rand() % n1;
                ++attempts;

                // Compare Selection Count of Elements
                if (rndnum[x].count > rndnum[i - 1].count && attempts < max_attempts) {
                    // Using Mersenne Twister PRNG
                    x = rand() % n1;
                    ++attempts;
                    rndnum[x].count++;
                }

                if ((x + z) >= j) {
                    x = (x + z) - j;
                } else {
                    x = x + z;
                }


            }
        }

        std::swap(rndnum[x], rndnum[j]);
        --n1;
        --j;
    }
}

// For counting the repetitions throughout the shuffled list
int countConsecutiveRepetitions(const std::vector<Element>& rndnum) {
    int consecutiveRepetitions = 0;

    for (size_t i = 1; i < rndnum.size(); ++i) {
        if (haveSameAttributes(rndnum[i], rndnum[i - 1])) {
            ++consecutiveRepetitions;
        }
    }
    return consecutiveRepetitions;
}

std::vector<int> countConsecutiveRepetitionsPerAttribute(const std::vector<Element>& rndnum) {
    int consecutiveRepetitions1 = 0;
    int consecutiveRepetitions2 = 0;
    int consecutiveRepetitions3 = 0;
    int consecutiveRepetitions4 = 0;
    int consecutiveRepetitions5 = 0;

    for (size_t i = 1; i < rndnum.size(); ++i) {
        if (rndnum[i].attribute1 == rndnum[i - 1].attribute1) {
            ++consecutiveRepetitions1;
        }
        if (rndnum[i].attribute2 == rndnum[i - 1].attribute2) {
            ++consecutiveRepetitions2;
        }
        if (rndnum[i].attribute3 == rndnum[i - 1].attribute3) {
            ++consecutiveRepetitions3;
        }
        if (rndnum[i].attribute4 == rndnum[i - 1].attribute4) {
            ++consecutiveRepetitions4;
        }
        if (rndnum[i].attribute5 == rndnum[i - 1].attribute5) {
            ++consecutiveRepetitions5;
        }
    }
    int totalConsecutiveAttributes = consecutiveRepetitions1 + consecutiveRepetitions2 + consecutiveRepetitions3 + consecutiveRepetitions4 + consecutiveRepetitions5;
    return {consecutiveRepetitions1, consecutiveRepetitions2, consecutiveRepetitions3, consecutiveRepetitions4, consecutiveRepetitions5, totalConsecutiveAttributes};
}

    int main() {
    const int desiredSize = 50;
    const int numIterations = 1000;
    std::vector<Element> baseList = {
        {1, "Dragon", "Large", "Long", "Shoes", "Green"},
        {2, "Dragon", "Small", "Average", "Boots", "Green"},
        {3, "Dragon", "Small", "Short", "Slippers", "Red"},
        {4, "Dragon", "Medium", "Average", "Shoes", "White"},
        {5, "Dragon", "Large", "Long", "Boots", "Red"},
    };

    int totalConsecutiveRepetitions = 0;
    std::vector<int> totalConsecutiveRepetitionsPerAttribute(5, 0);

    srand(static_cast<unsigned int>(time(nullptr)));

    for (int iteration = 0; iteration < numIterations; ++iteration) {
        std::vector<Element> rndnum;



        // Repeat the base list to achieve the desired size
        while (rndnum.size() < desiredSize) {
            rndnum.insert(rndnum.end(), baseList.begin(), baseList.end());
        }

        // Trim the excess elements
        rndnum.resize(desiredSize);

        enhancedShuffle(rndnum);

        // Display each element with its attributes (Optional)
//        for (const auto& element : rndnum) {
//            std::cout << "Value: " << element.value
//                      << ", Attribute1: " << element.attribute1
//                      << ", Attribute2: " << element.attribute2
//                      << ", Attribute3: " << element.attribute3
//                      << ", Attribute4: " << element.attribute4
//                      << ", Attribute5: " << element.attribute5
//                      << ", Count: " << element.count << std::endl;
//        }

        int consecutiveRepetitions = countConsecutiveRepetitions(rndnum);
        totalConsecutiveRepetitions += consecutiveRepetitions;

        std::vector<int> consecutiveRepetitionsPerAttribute = countConsecutiveRepetitionsPerAttribute(rndnum);
        for (int i = 0; i < 5; ++i) {
            totalConsecutiveRepetitionsPerAttribute[i] += consecutiveRepetitionsPerAttribute[i];
        }

        std::cout << "\nConsecutive repetitions in iteration " << iteration + 1 << ": " << consecutiveRepetitions << std::endl;
        std::cout << "---------------------------------------------\n";

    }

    int totalAttributeCounts = 0;
    for (int count : totalConsecutiveRepetitionsPerAttribute) {
        totalAttributeCounts += count;
    }

    std::cout << "\nTotal Consecutive repetitions across all iterations: " << totalConsecutiveRepetitions << std::endl;

    return 0;
}

RESULTS: RAND

  • CASE 1: 2292
  • CASE 2: 2222
  • CASE 3: 2231
  • CASE 4: 2243
  • CASE 5: 2268

COMPARISON: TOTAL CONSECUTIVE REPETITIONS PER CASE

MERSENNE:

  • CASE 1: 2317
  • CASE 2: 2222
  • CASE 3: 2325
  • CASE 4: 2331
  • CASE 5: 2314

RAND

  • CASE 1: 2292
  • CASE 2: 2222
  • CASE 3: 2231
  • CASE 4: 2243
  • CASE 5: 2268

The results for both are inconsistent, there are times when I test again Mersenne seems to be lower and Rand appears higher, but most of the time the Rand has much lower consecutive repetitions. I was expecting to have lower results when using Mersenne. Does that mean that Mersenne is not an enhancement in my application to use?

12
  • I don't think that this is as scientific as using software that specializes in this kind of testing such as diehard suite or the suite of the German BSI. Those are for cryptographic algorithms, but in principle they test the quality of the distribution. Note that these are normally run on multiple GiB of data. Commented Mar 20, 2024 at 4:17
  • 1
    Frequency of repetitions, consecutive or otherwise, is not a measure of randomness nor of quality of a random number generator. You need to look at properties of the distribution of values produced. Whatever the distribution is, there is always a non-zero chance of repetition, and of consecutive repetitions - a generator with no repetitions (or no consecutive repetitions) would often be pretty poor by various measures. Commented Mar 20, 2024 at 4:19
  • Thank you for these comments! What do you guys suggest that I do to test that using Mersenne here is better than using Rand, not basing on the frequency of repetitions? Commented Mar 20, 2024 at 5:21
  • 1
    Why do you equate "apparent randomness" with "smaller number of consecutive repetitions"? If you're seeking a random choice of (say) what type of critter is coming through a door, it is actually quite reasonable that two critters of the same type sometimes come through, one after the other. People are quite used to the notion of throwing a die, and (say) getting two consecutive equal values (in fact, on every throw, there is a one in six chance that the value thrown will be the same as the previous one). Commented Mar 20, 2024 at 12:31
  • 1
    And, if you're doing shuffling, just make sure the set you're shuffling has unique values, and has a large enough set of values. Then it doesn't matter whether the random number generator produces consecutive values the same - you're going to be calling the generator multiple times to shuffle anyway - and, unless the number of consecutive repeats is comparable with (a significant proportion of) the number of values being shuffled, the impact of the repeats will be insignificant anyway. Commented Mar 20, 2024 at 12:37

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.