Более общий случай инструкции bsf и RNG/ГСЧ

Тема в разделе "WASM.A&O", создана пользователем Quantum, 28 сен 2006.

  1. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Пытаюсь упростить следующую задачу:

    На входе имеем произвольное 64-битное число.

    Вычисляем кол-во единиц в двоичном представлении данного числа тем самым классическим безбранчевым методом, что описан в Уоррене. Кол-во единиц обозначим символом n.

    Далее используем генератор случайных чисел, чтобы получить число в промежутке [0, n - 1]. Обозначим это число символом m.

    Возвращаем позицию m-ной единицы во входном 64-битном значении.

    Вот и всё.

    Таким образом, имеем "продвинутый" ГСЧ с распределением, отвечающим требованиям какой-то другой задачи (общую задачу приводить, думаю, не стоит, т.к. это будет отдельная тема, возможно) и диапазоном [0, 63].

    Как видите, задача на данном этапе решается в 3 шага. Есть мнение, что можно организовать аналогичный ГСЧ более простым образом.

    Теперь более конкретный вопрос :) Как бы соптимизировать 3й шаг, т.е. вычисление позиции m-ной единицы. В Уоррене есть алгоритм подсчёта ведущих нулей, т.е. вычисление позиции первой единицы в заданном числе, но мне нужна не первая, а m-ная... Инструкция bsf тоже ищет именно пурвую единицу и есть подозрение, что в x64 этой инструкции уже нет.
     
  2. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Quantum
    У меня есть подозрение, что если числа на входе и m распределены равномерно, то в выходной последовательности тоже будут равномерно распределённые числа. Зачем тебе такой навороченный генератор равномерно распределённых чисел?
     
  3. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Black_mirror
    m выдаёт генератор с равномерным распределением (конкретно Mersenne Twister). 64-битное число на входе берётся не из ГСЧ, а подбирается таким образом, чтобы распределение комплексного ГСЧ максимально приближалось к некоторой полиномиальной функции. Таким образом, правильно подобрав это ключевое число можно получить ГСЧ с практически любым распределением и без лишних затрат на арифметику. "Точность" аппроксимации зависит от разрешения ключевого слова (пока 64 бит, но можно повысить и до 128 бит и т.д.)
     
  4. EvilsInterrupt

    EvilsInterrupt Постигающий азы дзена

    Публикаций:
    0
    Регистрация:
    28 окт 2003
    Сообщения:
    2.428
    Адрес:
    Russia
    Quantum
    Может пригодиться
     
  5. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    EvilsInterrupt
    Спасибо! В качестве первичного ГСЦ вполне годится даже сишный random(). Наиболее критичным вопросом пока остаётся 3й шаг, т.е. вычисление позиции заданной единицы в 64-битном числе. bsf для этой цели совсем не рулит.
     
  6. EvilsInterrupt

    EvilsInterrupt Постигающий азы дзена

    Публикаций:
    0
    Регистрация:
    28 окт 2003
    Сообщения:
    2.428
    Адрес:
    Russia
    Quantum
    Если найдешь док-во, что заявленный период в данном сорце, действительно верен, напиши!
     
  7. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Quantum
    Первая версия не пригодная для практического применения:
    Код (Text):
    1. bitm:
    2.         mov ebx,eax
    3.         shr ecx,1
    4.         adc ebx,ebx
    5.         xor ebx,eax
    6.         lea edx,[ebx*4]
    7.         xor ebx,edx
    8.         imul edx,ebx,$10
    9.         xor ebx,edx
    10.         imul edx,ebx,$100
    11.         xor ebx,edx
    12.         imul edx,ebx,$10000
    13.         xor ebx,edx
    14.         and eax,ebx
    15.         lea ebx,[eax-1]
    16.         test eax,ebx
    17.         jnz bitm
    18.         bsf eax,eax
    19.         ret
    На входе eax - число, ecx - m, результат в eax.
     
  8. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Табличный метод:
    Код (Text):
    1. bitm:
    2.         xor eax,eax
    3.         mov ebx,bit_count
    4.         mov edx,esi
    5.     .l0:
    6.         lodsb
    7.         sub cl,[ebx+eax]
    8.         jge .l0
    9.         add cl,[ebx+eax]
    10.         sub esi,edx
    11.         movzx eax,byte [bit_index+eax*8+ecx]
    12.         lea eax,[eax+esi*8-8]
    13.         ret
    14.  
    15. bit_count:;256 байт
    16. repeat 256
    17.     v = %-1
    18.     v = (v and $55) + ((v shr 1) and $55)
    19.     v = (v and $33) + ((v shr 2) and $33)
    20.     db (v and 15) + (v shr 4)
    21. end repeat
    22.  
    23. bit_index: ;256*8=2Кб
    24. repeat 256
    25.     v = %-1
    26. repeat 8
    27.     n=%
    28.     c = 0
    29. repeat 8
    30.     if v and (1 shl (%-1))
    31.         n=n-1
    32.         if n
    33.         else
    34.             c=(%-1)
    35.         end if
    36.     else
    37.     end if
    38. end repeat
    39.     db c
    40. end repeat
    41. end repeat
    esi - указатель на число, ecx - m (не более 255), результат в eax.
     
  9. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Black_mirror
    Извини, что сразу не ответил, но у меня пол дня ушло, чтобы осмыслить второй код :) Сильно! Коммерческое применение этого алгоритма пока не планируется, но, возможно, будет статья в каком-нибудь научном издании и я позабочусь, чтобы твой копирайт сохранился. Спасибо большое!

    EvilsInterrupt
    В принципе, период всегда меньше или равен диапазону (2 exp n - 1, n - кол-во бит в сиде). Если в сиде меньше бит, то период заявлен с завышением.
     
  10. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Изменив немного код и таблицу можно выкинуть одну команду:
    Код (Text):
    1. bitm:
    2.         xor eax,eax
    3.         mov ebx,bit_count
    4.         mov edx,esi
    5.     .l0:
    6.         lodsb
    7.         sub cl,[ebx+eax]
    8.         jge .l0
    9. ;здесь был [b]add[/b]
    10.         sub esi,edx
    11.         movzx eax,byte [bit_index+eax*8+ecx[b]-248[/b]]
    12.         lea eax,[eax+esi*8-8]
    13.         ret
    14.  
    15. ;таблица bit_count не меняется
    16.  
    17. bit_index: ;256*8=2Кб
    18. repeat 256
    19.     v = %-1
    20. repeat 8
    21.     n = [b]8-%[/b]
    22.     c = 0
    23. repeat 8
    24.     if v and ([b]$80 shr (%-1)[/b])
    25.         if n
    26.         else
    27.             c=[b]7-(%-1)[/b]
    28.         end if
    29.         n=n-1
    30.     else
    31.     end if
    32. end repeat
    33.     db c
    34. end repeat
    35. end repeat
    Quantum
    Я так и не понял что происходит с 64х битным числом, оно просто является параметром генератора или каким либо образом меняется при каждом вызове?
    Что за полиномиальная функция к которой приближается распределение?
    Если в 64х битном числе один из битов нулевой то на выходе просто не будет чисел равных его индексу. Или в интервале [0,63] некоторые значения могут вообще отсутствовать?
     
  11. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Black_mirror
    Это число подбирается, чтобы распределение имело нужную форму (Гауса, Пуассо с некоторым параметром ламбда, фрактальную и т.д.). Обычно, она задаётся один раз (в самом начале) и не изменяется для каждого этапа.

    Распределение зависит от плотности и количества единиц на каждом этапе данной формулы. Я назвал эту функцию полиномиальной, потому что 64-битное число - это полином с коэффициентами от 0 до 63. К примеру, если все биты установлены, имеем равномерное распреление (при условии, что первичный ГСЧ имеет равномерное распределение).

    Верно.

    Можно сказать, что эти значения имеют вероятность = 0, если данное число константно. Теоретически это не совсем правильно (нулевая вероятность не должна означать, что значений не будет вообще), но на практическую сторону задачи этот факт никак не отражается.