Mersenne vs Rand: Why do I get more total consecutive repetitions when using Mersenne compared to Rand? C++

70 views Asked by At

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?

0

There are 0 answers