Самый быстрый способ сгенерировать случайное логическое значение

87

Итак, есть несколько способов создания случайного bool в C #:

  • Использование Random.Next (): rand.Next(2) == 0
  • Использование Random.NextDouble (): rand.NextDouble() > 0.5

Есть ли разница? Если да, то какой на самом деле имеет лучшую производительность? Или есть другой способ, которого я не видел, он может быть даже быстрее?

timedt
источник
17
ericlippert.com/2012/12/17/performance-rant
Остин Салонен
7
Это действительно узкое место?
Брайан Расмуссен,
2
На самом деле без его запуска (потому что любой метод будет смехотворно быстрым), я предполагаю использовать NextBytesдля предварительного заполнения байтового массива, использовать его BitArrayдля преобразования в коллекцию логических значений и извлекать эти логические значения из a Queueдо тех пор, пока он не будет очищен, а затем повторить процесс. В этом методе вы используете рандомизатор только один раз, поэтому любые накладные расходы, которые он создает, возникают только тогда, когда вы пополняете очередь. Это может быть полезно при работе с безопасным генератором случайных чисел, а не с обычным Randomклассом.
Джо Энос,
2
@JoeEnos MS испортила реализацию NextBytes, так что она на удивление медленная
CodesInChaos
1
@CodesInChaos Вау, это интересно - я просто просмотрел это в дизассемблере, чтобы увидеть, о чем вы имели в виду: buffer[i] = (byte)(this.InternalSample() % 256);- Я предполагаю, что это то, о чем вы говорите, что они могли взять это случайное целое число и разделить его на 3 байта , заполняя массив байтов примерно на 1/3 работы. Интересно, была ли для этого причина или это просто упущение со стороны разработчиков.
Джо Энос

Ответы:

72

Первый вариант - rand.Next(2)исполняет за кулисами следующий код:

if (maxValue < 0)
{
    throw new ArgumentOutOfRangeException("maxValue",
        Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", new object[] { "maxValue" }));
}
return (int) (this.Sample() * maxValue);

а для второго варианта - rand.NextDouble():

return this.Sample();

Поскольку первый вариант включает maxValueпроверку, умножение и приведение, второй вариант, вероятно, быстрее .

Авиран Коэн
источник
Спасибо, это все, что я хотел знать.
timedt
5
Мои собственные тайминги говорят, что второй вариант примерно на 5% быстрее первого.
ClickRick
60

Небольшое улучшение для второго варианта :

Согласно MSDN

public virtual double NextDouble()

возвращается

Число с плавающей запятой двойной точности, большее или равное 0,0, но меньшее 1,0.

Поэтому, если вам нужен равномерно распределенный случайный логический объект, вы должны использовать >= 0.5

rand.NextDouble() >= 0.5

Диапазон 1: [0,0 ... 0,5 [
Диапазон 2: [0,5 ... 1,0 [
| Диапазон 1 | = | Диапазон 2 |

ДаРич
источник
9

Самый быстрый. При вызове метода Random.Nextнакладные расходы меньше. Приведенный ниже метод расширения работает на 20% быстрее Random.NextDouble() > 0.5и на 35% быстрее Random.Next(2) == 0.

public static bool NextBoolean(this Random random)
{
    return random.Next() > (Int32.MaxValue / 2);
    // Next() returns an int in the range [0..Int32.MaxValue]
}

Быстрее самого быстрого. RandomИспользуя уловки, можно сгенерировать случайные логические значения с классом еще быстрее. 31 значащий бит сгенерированного intможет использоваться для 31 последующего логического вывода. Реализация ниже на 40% быстрее, чем ранее заявленная как самая быстрая.

public class RandomEx : Random
{
    private uint _boolBits;

    public RandomEx() : base() { }
    public RandomEx(int seed) : base(seed) { }

    public bool NextBoolean()
    {
        _boolBits >>= 1;
        if (_boolBits <= 1) _boolBits = (uint)~this.Next();
        return (_boolBits & 1) == 0;
    }
}
Теодор Зулиас
источник
Благодарность! Тем, кто использует UnityEngine для написания скриптов, обязательно используйте System.Random, а не UnityEngine.Random, поскольку это не одно и то же!
DonCarleone
6

Я проводил тесты с секундомером. 100000 итераций:

System.Random rnd = new System.Random();
if (rnd.Next(2) == 0)
     trues++;

ЦП любят целые числа, поэтому метод Next (2) был быстрее. 3700 против 7500 мс, что довольно много. Также: я думаю, что случайные числа могут быть узким местом, я создавал около 50 на каждый кадр в Unity, даже с крошечной сценой, которая заметно замедляла мою систему, поэтому я также надеялся найти метод для создания случайного bool. Так что я тоже попробовал

if (System.DateTime.Now.Millisecond % 2 == 0)
       trues++;

но вызов статической функции был еще медленнее - 9600 мс. Стоит попробовать. Наконец, я пропустил сравнение и создал только 100 000 случайных значений, чтобы убедиться, что сравнение int и double не влияет на прошедшее время, но результат был почти таким же.

Фредерик Штайнмец
источник
1
DateTime.Now, как известно, медленный. В идеале, чтобы сделать это быстро, следует использовать аппаратно-зависимые решения или, по крайней мере, ОС.
Do-do-new
Используйте DateTime.UtcNow, это намного быстрее, чем DateTime.Now.
Theodor Zoulias