информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Сетевые кракеры и правда о деле ЛевинаВсе любят медSpanning Tree Protocol: недокументированное применение
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Google заблокировала 2 с лишним... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Я тоже сначала подумал так и отмел этот вариант, но... 15.06.04 16:16  Число просмотров: 1503
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Подбирать динамически совершенно нереально, точнее говоря
> невозможно.
> Так что сортировка - самый оптимальный вариант.
Я тоже сначала подумал так и отмел этот вариант, но насколько я помню a и b надо подбирать в зависимости от разложения модуля на сомножители. Если модуль - постоянный (например, алгоритм нужен для перетасовывания карт), то и требования к a и b будут постоянными.

Ну или если в качестве модуля (M1) брать степень ближайшую бОльшую степень двойки: разложение тривиально, требования - тоже (не помню точно, но кажется множитель должен быть сравним с 3 по модулю 4, приращение - нечетно, но за достоверность не отвечаю), то числа последовательности M < seed < M1 можно просто отбрасывать. В худшем случае (M = 2^n + 1) такой алгоритм даст максимум M1 = 2^(n+1) проходов. А M1/M ~ 2, то бишь в худшем случае время работы ~ 2*N (здесь N == M это размер таблицы)

Повторюсь, что вариант со степенью двойки нужно брать только если число элементов таблицы тоже динамическое и раскладывать его на простые, чтобы удовлетворить требования максимального цикла не очень хочется.
<programming>
Подскажите быстрый и эффективный алгоритм перестановки элементов массива в случайном порядке... 15.06.04 12:09  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка>
Задача, насколько я понимаю, сводится к написанию некоего Генератора ПсевдоСлучайных Чисел, который:
1) Генерирует целые ПСЧ в заданном диапазоне (N1, N2);
2) ПСЧ никогда не повторяются;
3) Кол-во полученных ПСЧ равно кол-ву целых чисел в этом диапазоне N2 - N1 (что следует из предыдущих пунктов).

Можно, конечно, прикрутить обычный ГПСЧ, но он не удовлетворяет указанным выше параметрам и прийдётся делать лишние движения для фильтрации «неправильных» чисел.

Заранее всем большое спасибо за советы!
Всем спасибо за «мозговой штурм» ;-) Остановился на… 15.06.04 17:22  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка>
сортировке с генератором, юзающим RDTSC.

Вариант с линейным конгруэнтным генератором отмёл по причине ненужной сложности...
Оптимизация сортировки 16.06.04 10:20  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> сортировке с генератором, юзающим RDTSC.
>
> Вариант с линейным конгруэнтным генератором отмёл по
> причине ненужной сложности...
Как резонно заметил leo, если результат сравнения никак не зависит от самих элементов (не обязательно значений, можно с каждым элементом сопоставить случайное число, все равно при сравнении одних и тех же элементов будет получаться всегда один и тот же результат), то любой алгоритм сортировки будет выполняться за время теоретического "худшего случая", если это не важно, то можно не заморачиваться.

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

Перед сортировкой вычисляем salt. Результатом сравнения двух чисел a и b можно взять какой нибудь бит хеша h(a, b, salt). Замечание: хеш не обязательно должен быть криптографически стойким и прочая - чай не для криптографии стараемся. Пример (не оптимальный, но показательный):

bool
compare(int a, int b) {
	static int salt = (int)(rand()) << 16 | rand();
	static int bit = rand() % 20 + 6;	// Младшие биты сами по себе не случайные
							// Старшие биты тоже на фиг на всякий случай
	return (bool)((a * b * salt) & (2 ^ bit));
}

---
Воспользоваться следует стандартным ГПСЧ. Сузить его... 15.06.04 13:16  
Автор: DPP <Dmitry P. Pimenov> Статус: The Elderman
Отредактировано 15.06.04 13:17  Количество правок: 1
<"чистая" ссылка>
> Задача, насколько я понимаю, сводится к написанию некоего
> Генератора ПсевдоСлучайных Чисел, который:
> 1) Генерирует целые ПСЧ в заданном диапазоне (N1, N2);
> 2) ПСЧ никогда не повторяются;
> 3) Кол-во полученных ПСЧ равно кол-ву целых чисел в этом
> диапазоне N2 - N1 (что следует из предыдущих пунктов).
>
> Можно, конечно, прикрутить обычный ГПСЧ, но он не
> удовлетворяет указанным выше параметрам и прийдётся делать
> лишние движения для фильтрации «неправильных» чисел.
>
> Заранее всем большое спасибо за советы!

Воспользоваться следует стандартным ГПСЧ. Сузить его диапазон (если надо) можно так: y = rnd() % d, получим ПСЧ в диапазоне [0,d), ширина = d. Для смещения диапазона в выше указанном случае: y = rnd() % (n2 - n1 + 1) + n1, если концы входят в диапазон.
Ближе к делу:
Берем массив, размерностью n2 - n1 + 1 (опять же если концы входят), заполняем его числами от n1 до n2. Далее циклом пробегаем по массиву, каждый раз генеря случайное число в диапазоне от начального индекса массива, до конечного. Меняем значения элементов массива, на которые ссылается последовательный счетчик и случайным образом сгенеренный индекс.
Я вижу это несколько по другому 15.06.04 12:24  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
Берешь ЛЮБОЙ алгоритм сортировки, но вместо сравнения элементов генерируешь случайный бит и выполняешь все те же самые действия. В STL-е даже менять ничего не придется - просто в шаблоне указать свою операцию

bool less<class T>(T v1, T v2) {return rand % 1;}

Таким образом массив будет ОТСОРТИРОВАН случайно.
Не совсем правильно 15.06.04 12:57  
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 15.06.04 13:08  Количество правок: 1
<"чистая" ссылка>
Использовать сортировку- идея хорошая, но именно так как предложено - некорректно.
При "замене" less() на rand() и хорошей сортировке (а-ля qsort), примерно половина элементов сохранят порядок следования.

Нужно сортировать пары {value_for_compare = rand(); pointer = &origin}.
И еще стандартный rand() дает очень плохие псевдослучайные числа.

Как вариант:
unsigned rand_seed;

unsigned rand2()
{
    __asm
    {
        rdtsc
        xor eax, rand_seed
        imul eax, 1664525ul
        add eax, 1013904223ul
        mov rand_seed, eax
    }
}

---
Не сохранят. но при любой сортировке, но хорошем rand() 15.06.04 14:34  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Использовать сортировку- идея хорошая, но именно так как
> предложено - некорректно.
> При "замене" less() на rand() и хорошей сортировке (а-ля
> qsort), примерно половина элементов сохранят порядок
> следования.
Не сохранят. Но при ЛЮБОЙ сортировке, но хорошем rand()

> Нужно сортировать пары {value_for_compare = rand(); pointer
> = &origin}.
То же самое. Сравнение двух rand() будет давать один случайный бит (при хорошем генераторе)

> И еще стандартный rand() дает очень плохие псевдослучайные
> числа.
Это да. Но это был всего лишь пример. Кроме того, как резонно заметили ниже, использовать только один бит из 16 сгенеренных - явный перебор.

#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

using namespace std;

bool compare(int, int) {return (bool)(rand() % 2);}

void
main() {
	vector<int> v;

	srand(time(NULL));

	v.resize(20);

	for (int i = 0; i < v.size(); i++)
		v[i] = i;

	sort(v.begin(), v.end(), compare);

	for (i = 0; i < v.size(); i++)
		cout << v[i] << " ";

	cout << endl;
}

6 14 12 11 13 15 4 3 2 18 5 0 7 8 10 9 1 16 17 19

---
Ок, но сортировка может занять больше времени 15.06.04 15:38  
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 15.06.04 15:40  Количество правок: 1
<"чистая" ссылка>
Oк, насчет распределения я как-то не додумал, на самом деле все должно быть хорошо.
Но если вместо сравнения использовать rand(), то сортировка может занять больше времени.
Конечно все зависит от алгоритма, и как вариант - продолжаться бесконечно.

#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace ::std;

typedef pair<int, int> item;
bool compare(const item &a, const item &b) {return a.second > b.second;}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<item> v;
    srand(time(NULL));

    v.resize(20);

    for (int i = 0; i < v.size(); i++)
    {
        v[i].first = i;
        v[i].second = rand();
    }

    sort(v.begin(), v.end(), compare);

    for (i = 0; i < v.size(); i++)
        cout << v[i].first << " ";

    cout << endl;
    return 0;
}

---
Возможно 15.06.04 16:02  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Oк, насчет распределения я как-то не додумал, на самом деле
> все должно быть хорошо.
> Но если вместо сравнения использовать rand(), то сортировка
> может занять больше времени.
> Конечно все зависит от алгоритма, и как вариант -
> продолжаться бесконечно.
Да, действительно, быстрая сортировка в моем примере будет работать как в худшем случае (квадратичное время). Не бесконечное, конечно, но и не самое эффективное
Не жирно ли юзать Rand() для генерирования случайного бита? Может как-то по-другому? И алгоритмы сортировки тоже ресурсоёмкие... IMHO должна быть целая группа нужных мне ГПСЧ ;-) 15.06.04 12:42  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка>
Жирно. Именно поэтому словами я написал, что нужен только один бит [update] 15.06.04 14:40  
Автор: amirul <Serge> Статус: The Elderman
Отредактировано 15.06.04 15:04  Количество правок: 2
<"чистая" ссылка>
А rand() % 2 просто самый короткий (но не самый эффективный) метод генерации одного бита, что вполне подходит для примера.

Сортировка - самый эффективный метод перемешивания массива чисел так, чтобы каждый элемент занял случайную позицию. Если пытаться сгенерить таблицу, то оверхед будет из-за необходимости УНИКАЛЬНЫХ случайных чисел, что приведет к квадратичному времени генерации таблицы от размера исходных данных.

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

Да, вспомнил о линейном конгруэнтном генераторе.
seed = (a*seed + b) mod M;

При правильно подобранных a и b генератор пробегает все числа от 0 до [M-1]

Как именно их надо подбирать не помню - спрашивай у гугля.
ЗЫ: Подбирать их тебе надо динамически. Не факт, что эта задача окажется быстрее сортировки (вернее, все зависит от M)
о линейном конгруэнтном 15.06.04 15:46  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
> Да, вспомнил о линейном конгруэнтном генераторе.
> seed = (a*seed + b) mod M;
>
> При правильно подобранных a и b генератор пробегает все
> числа от 0 до [M-1]
>
> Как именно их надо подбирать не помню - спрашивай у гугля.
> ЗЫ: Подбирать их тебе надо динамически. Не факт, что эта
> задача окажется быстрее сортировки (вернее, все зависит от
> M)

Подбирать динамически совершенно нереально, точнее говоря невозможно.
Так что сортировка - самый оптимальный вариант.
Я тоже сначала подумал так и отмел этот вариант, но... 15.06.04 16:16  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Подбирать динамически совершенно нереально, точнее говоря
> невозможно.
> Так что сортировка - самый оптимальный вариант.
Я тоже сначала подумал так и отмел этот вариант, но насколько я помню a и b надо подбирать в зависимости от разложения модуля на сомножители. Если модуль - постоянный (например, алгоритм нужен для перетасовывания карт), то и требования к a и b будут постоянными.

Ну или если в качестве модуля (M1) брать степень ближайшую бОльшую степень двойки: разложение тривиально, требования - тоже (не помню точно, но кажется множитель должен быть сравним с 3 по модулю 4, приращение - нечетно, но за достоверность не отвечаю), то числа последовательности M < seed < M1 можно просто отбрасывать. В худшем случае (M = 2^n + 1) такой алгоритм даст максимум M1 = 2^(n+1) проходов. А M1/M ~ 2, то бишь в худшем случае время работы ~ 2*N (здесь N == M это размер таблицы)

Повторюсь, что вариант со степенью двойки нужно брать только если число элементов таблицы тоже динамическое и раскладывать его на простые, чтобы удовлетворить требования максимального цикла не очень хочется.
Не так все просто 15.06.04 18:42  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
Не все так просто. Одно дело найти а и b чтобы просто получился конгруэнтный генератор, и совсем другое дело чтобы он был хороший в плане псевдо-случайности. Поэтому хорошие тройки a/b/M - настоящие находки. А то ведь a == b == 1 - универсальный случай :)

Но мы уже явно "пере-инженириваем"...
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach