Что быстрее? по модулю int или разделить int на MAX_INT, чтобы получить число с плавающей запятой, затем умножить на требуемое значение модуля и привести обратно к int? - PullRequest
0 голосов
/ 05 июня 2019

Что быстрее:

random() % 100;

или

static_cast<int>((random() / 4294967296) * 100);

Я действительно не знаю, как правильно выполнить эталонный тест, и то, что быстрее появляется на моем компьютере, может не сработатьпо другим, поэтому я смиренно задаю этот вопрос мудрому народу на Stackoverflow

1 Ответ

4 голосов
/ 05 июня 2019

Генерация случайных чисел может быть выполнена с помощью rand() или std::mt19997. Последний является предпочтительным, я все еще тестировал для обоих случаев. (Visual Studio 2017 Community x64). Я использую фиктивную переменную, чтобы компилятор не мог игнорировать случайные операторы генерации. rand() возвращает int, а std::mt19937 возвращает std::uint32_t. Поэтому, чтобы уменьшить количество приведений, я использую 2 фиктивные переменные.

#include <iostream>
#include <random>
#include <chrono>
#include <limits>
#include <string>
#include <cstdlib>

namespace util {
    constexpr std::size_t loop{ 10'000'000u };
    std::mt19937 engine{ std::random_device{}() };
    int rand_dummy{ 0 };
    std::uint32_t mt19937_dummy{ 0u };
}

void rand_mod() {
    for (std::size_t i = 0u; i < util::loop; ++i) {
        util::rand_dummy = (rand() % 100);
    }
}
void rand_div() {
    for (std::size_t i = 0u; i < util::loop; ++i) {
        util::rand_dummy = static_cast<int>(static_cast<double>(rand()) / RAND_MAX * 100);
    }
}

void mt19937_mod() {
    for (std::size_t i = 0u; i < util::loop; ++i) {
        util::mt19937_dummy = (util::engine() % 100u);
    }
}
void mt19937_div() {
    for (std::size_t i = 0u; i < util::loop; ++i) {
        util::mt19937_dummy = static_cast<std::uint32_t>(static_cast<double>(util::engine()) / std::numeric_limits<std::uint32_t>::max() * 100u);
    }
}

void benchmark(void(*f)(void), const std::string& name) {
    auto t1 = std::chrono::high_resolution_clock::now();
    f();
    auto t2 = std::chrono::high_resolution_clock::now();
    std::cout << name << std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count() / 1e6 << "ms\n";
}

int main() {
    srand(std::random_device{}());

    benchmark(rand_mod,    "rand()       | mod: ");
    benchmark(rand_div,    "rand()       | div: ");
    std::cout << "---------------------------\n";
    benchmark(mt19937_mod, "std::mt19937 | mod: ");
    benchmark(mt19937_div, "std::mt19937 | div: ");

    return util::rand_dummy + util::mt19937_dummy;
}

оптимизации отключены (/ Od):

rand()       | mod: 956.128ms
rand()       | div: 796.235ms
---------------------------
std::mt19937 | mod: 437.885ms
std::mt19937 | div: 584.477ms

полная оптимизация (/ Ox):

rand()       | mod: 276.092ms
rand()       | div: 262.224ms
---------------------------
std::mt19937 | mod: 61.4312ms
std::mt19937 | div: 103.38ms

  • std::mt19937 в обоих случаях быстрее

  • для std::mt19937 модуль выигрывает у деления

  • для rand() делений выигрывает над модулем

Так что это зависит от того, какой вы используете. Поскольку std::mt19937 превосходит rand(), ответ должен быть следующим: модуль быстрее деления.

> почему rand() считается вредным>


Обратите внимание, что вы также не должны делать:

engine() % 100;

Вместо этого используйте std::uniform_int_distribiution(0, 99)(engine);

[engine является std::mt19937]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...