" title="Написать письмо">Написать письмо
На выжить после операций проктологии
2200 4002 2461 6363

Статистика

Пользователи : 1
Статьи : 2533
Просмотры материалов : 10955835
 
Быстрые генераторы unsigned int (05.11.2026). Печать E-mail
2026 - Ноябрь
05.11.2026 00:00
Save & Share
7 материалов было написано по теме быстрой генерации данных (раз, два, три, четыре, пять, научный шесть и издевательско-итоговый 7). Пришло время предъявить самописно-ИИшные маленькие генераторы, как рабочие (при этом ИИ жестоко обманул, поэтому его вложения в эти генераторы считаю нулевыми или отрицательными: так поднасрать - это ещё надо уметь).


Самый идеальный: 1.08ГБ/с при частоте потока 1.25ГГц, в 18.4 раза быстрее штатного rand() Borland C++ Builder v.6.0, unsigned int, выход 0...4294967295, без входных параметров, нормальное распределение чисел, коэффициенты энтропии Шеннона на блоки 200МБ 3.3 и 512Б в его составе средний 3.3 (естественно: ни о каком шифровании речи не идёт - только генерация, все ресурсы - на неё).

Распределение оценивалось, вызывая генератор 4294967296 раз (не попадитесь в ловушку последнего значения: только __int64 в цикле) и группируя вызовы по сотням чисел (не хватает RAM - массив результатов размерностью 429496723). Все числа в массиве, сохранённом в файл (строка - получаемое число минус 1, число - сколько раз сгенерировано), были равны 100 (только в первой сотне 50). Куда делось ещё 46 измерений первой сотни - непонятно, но результат распределения - практически идеальный, никакого графика не нужно: исходным кодом всё проверил.


Серьёзный минус: псевдохаос вместо хаоса - всегда выдаёт определённую последовательность чисел при старте программы. Решается просто: при старте ПО - прокрутить генератор произвольное количество раз, используя медленный random(255) как входной параметр - и прибавляя его потом ко всем числам генератора.

unsigned int uiFast_Random()
{
    static unsigned int uiResult = 123456789U;

    uiResult = uiResult * 1664525U + 1013904223U; //Пусть переполняется: проблемы нет.

    return uiResult;
}

На основе этого генератора, рождается генератор unsigned int с входным параметром максимума. ИИ очень сильно поднасрал, предложив для результата предыдущего генератора использовать побитовое И вместо %. Выигрыш в скорости вышел значительным, но при анализе входного параметра миллион и вызове (4294967296? Забыл) раз - получилось просто безумное распределение чисел: он пытался равномерно распределиться в диапазоне - но порождал только 128 чисел кучками и создавал их десятками миллионов раз.



Рассвирепел (правда, в текущем состоянии это было похоже на писк мышонка в мышеловке). Отключил мозги и написал это.

unsigned int uiFast_Random_Again(const unsigned int uiMax)
{
    static unsigned int uiResult_Again = 123456789U;

    again: uiResult_Again = uiResult_Again * 1664525U + 1013904223U; //Пусть переполняется: проблемы нет.

    if (uiResult_Again < uiMax) return uiResult_Again; else goto again; //Не включая сам предел.
}

Работает - безумно медленно; но у него обнаружился такой бонус, который перекрыл огромное время и сделал этот генератор жизнеспособным. Запустив его 14млн раз при входном числе 1млн - распределение чисел вышло нормальным: ровно по 14 раз каждое число вызвалось (до этого - ещё на 10млн проверил). Здесь - уже возникает сомнение в работе самописного алгоритма оценки распределения. Но изучение штатного random(1000000) ставит всё на свои места: у него не нормальное, а стандартное распределение (тут уже справа само число подписано, рядом с количеством его получения). Это доказывает работоспособность и алгоритма проверки, и теоретическую нормальность именно почисленного распределения чисел изначального генератора без параметров (после успешного теста порциями по 100шт).



Теперь - этот генератор с входным параметром надо ускорить. Сразу ясно несколько вещей: после этого он не будет с нормальным распределением (это очень сложная в поддержке величина), коэффициенты Шеннона не имеют смысла (зависят напрямую от входного параметра). Гугл предложил использовать % uiMax для uiResult - был послан: это уже делал, скорость падает раза в 3. Поэтому - опять окунание в говно под названием ассемблер, в попытке сделать ассемблерную вставку. Она - получилась: такое же стандартное распределение, как у %, - но скорость работы упала всего в 1.44 раза относительно генератора без параметра. Далее обнаружился прикол: генератор стал с другого числа старт давать: с % было 370032, а со вставкой - 214290. Ранее для попадания во все числа при входном параметре миллион было 13.1млн вызовов - стало 14.1млн.

Define - быстрее ассемблерной вставки. Удалось их скомбинировать - и алгоритм стал медленнее изначального в 1.34 раза. Но он перестал генерировать разные числа - и генерировал только одно... Поэтому публикуется прошлый вариант.

unsigned int uiFast_Random_ASM(const unsigned int uiMax)
{
    static unsigned int uiResult_ASM = 123456789U;

    uiResult_ASM = uiResult_ASM * 1664525U + 1013904223U;

    register unsigned int uiResult;
    
    asm
    {
        mov eax, uiResult_ASM //Умножение. eax - младшие биты, edx - старшие.
        mul uiMax
        mov uiResult, edx //Ну, старшие 32 бита и берём.
    }

    return uiResult;
}

График стандартного распределения третьего генератора (онлайн миллион точек не построить - только в Windows от 7 x64 и Office 2010 x64 - и всё виснет, и полный писец - еле скрин сделал после окончательного зависания). Какие-то числа редко выпадают, какие-то часто, - не нормальность - стандартность. И видно, что одно число - генератор-таки профукал. Ну, простим ему это.


Теперь, на основании этих генераторов, - можно и заполнять массивы, и делать другие типы данных: каждый из них - годится для своих задач. Замедление работы генератора - теперь на совести разработчика, плюс удобство использования: свои циклы, свои массивы, свои части заполнения этих массивов. А то массив внутрь добавил и число его элементов - сразу в 3 раза скорость и потерял.

Мои проекты по созданию генераторов изрядно замусорились. Нужно создать новый, объединить в нём всё лучшее, протестировать алгоритмы уже в чистовых условиях. Но вряд ли это изменит числа или строки, написанные здесь, - это будет генератор в генераторе с высоким коэффициентом Шеннона (о котором будет уже отдельный материал с бешеной скоростью >6.72ГБ/с: оптимизация и ускорение продолжаются - этот лимит уже пройден).

Можно ещё добавить четвёртый генератор, с уточнённой скоростью: long double с большим константным хвостом. Именно такой мне нужен для создания генератора в генераторе. Но никто не мешает вам для увеличения хаоса: пожертвовать скоростью - и добавить к целому числу ровно такую же дробную часть, а не константу. А то и двойную дробную часть по длине.

//0.89ГБ/с при частоте потока 1.25ГГц.
long double ldFast_Random()
{
    static unsigned int uiResult = 123456789U;

    uiResult = uiResult * 1664525U + 1013904223U; //Пусть переполняется: проблемы нет.

    return uiResult + 0.3696425965745; //Порождение дробной части сложением - быстрее деления.
}

Завтра - будут уточнения по материалу. Сырой он вышел - нужно дополнить и поправить изначальный текст незначительно.
Обновлено ( 05.11.2026 19:49 )
 
 

Последние новости


©2008-2026. All Rights Reserved. Разработчик - " title="Сергей Белов">Сергей Белов. Материалы сайта предоставляются по принципу "как есть". Автор не несет никакой ответственности и не гарантирует отсутствие неправильных сведений и ошибок. Вся ответственность за использование материалов лежит полностью на читателях. Размещение материалов данного сайта на иных сайтах запрещено без указания активной ссылки на данный сайт-первоисточник (ГК РФ: ст.1259 п.1 + ст.1274 п.1-3).

Много статей не имеет срока устаревания. Есть смысл смотреть и 2011, и даже 2008 год. Политика сайта: написать статью, а потом обновлять ее много лет.
Рекламодателям! Перестаньте спамить мне на почту с предложениями о размещении рекламы на этом сайте. Я никогда спамером/рекламщиком не был и не буду!
Top.Mail.Ru