Каково качество реализации класса Random в .NET?

У меня есть два вопроса относительно реализации класса Random в .NET Framework 4.6 (код доступен здесь):

  • В чем смысл установки аргумента Seed в 1 в конце конструктора? Кажется, это скопировано из Numerical Recipes в C (2-е изд.), Где это имело какой-то смысл, но в С# оно не имеет.

  • В книге (Численные рецепты в C (2-е изд.)) указано, что в поле inextp установлено значение 31, потому что:

Постоянная 31 является специальной; см. Кнут.

Однако в реализации .NET это поле имеет значение 21. Зачем? Остальная часть кода, похоже, внимательно следит за кодом из книги, за исключением этой детали.

Ответ 1

Что касается проблемы intexp, это ошибка, которая Microsoft подтвердила и отказалась исправлять из-за проблем с обратной совместимостью.

Действительно, вы обнаружили настоящую проблему с реализацией Random. Мы обсудили это в команде и с некоторыми нашими партнерами и пришли к выводу, что, к сожалению, мы не можем решить эту проблему прямо сейчас. Причина в том, что некоторые приложения полагаются на то, что при инициализации с одним и тем же семенем генератор создает одну и ту же псевдослучайную последовательность. Даже если изменение к лучшему, оно сломает приложения, которые сделали это предположение, как только они перешли к "фиксированной" версии.

Ответ 2

В другом контексте:

A назад я полностью проанализировал эту реализацию. Я нашел несколько отличий.

A первый (отлично) - это другое большое значение (MBIG). Numerical Recipies утверждает, что Кнут дает понять, что любое большое значение должно работать, поэтому это не проблема, и Microsoft разумно предпочла использовать наибольшее значение 32-битного целого числа.

Вторая - та константа, о которой вы говорили. Это большая сделка. Как минимум, это существенно уменьшит период. Сообщалось, что эффекты на самом деле хуже, чем это.

Но затем приходит еще одна особенно неприятная разница. В буквальном смысле это подразумевает смещение вывода (поскольку оно делает это напрямую), а также, вероятно, повлияет на период ГСЧ.

Итак, что это за второй вопрос? Когда .NET впервые появилась, Microsoft не понимала, что RNG, который они закодировали, был включен на обоих концах, и они задокументировали его как эксклюзивный на максимальном конце. Чтобы исправить это, команда безопасности добавила довольно злую строку кода: if (retVal == MBIG) retVal--;. Это очень к сожалению, поскольку правильное исправление буквально будет всего лишь 4 добавленными символами (плюс пробелы).

Правильное исправление заключалось бы в изменении MBIG на int.MaxValue-1, но переключить Sample() на использование MBIG+1 (т.е. продолжать использовать int.MaxValue). Это гарантировало бы, что этот образец имеет диапазон [0.0, 1.0), не вводя никакого смещения, и только изменяет значение MBIG, которое Numerical Recipies говорит, что Knuth сказал, что это прекрасно.