На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! правила раздела Алгоритмы
1. Помните, что название темы должно хоть как-то отражать ее содержимое (не создавайте темы с заголовком ПОМОГИТЕ, HELP и т.д.). Злоупотребление заглавными буквами в заголовках тем ЗАПРЕЩЕНО.
2. При создании темы постарайтесь, как можно более точно описать проблему, а не ограничиваться общими понятиями и определениями.
3. Приводимые фрагменты исходного кода старайтесь выделять тегами code.../code
4. Помните, чем подробнее Вы опишете свою проблему, тем быстрее получите вразумительный совет
5. Запрещено поднимать неактуальные темы (ПРИМЕР: запрещено отвечать на вопрос из серии "срочно надо", заданный в 2003 году)
6. И не забывайте о кнопочках TRANSLIT и РУССКАЯ КЛАВИАТУРА, если не можете писать в русской раскладке :)
Модераторы: Akina, shadeofgray
  
> Быстрая работа с числами в троичной системе
    Знает ли кто-нибудь быстрый алгоритм\юнит для работы с целыми (и довольно большими -- до 3^80) числами в троичной системе?
    Имеется в виду, заметно быстрее, чем с помощью стандартных операций div 3, mod 3 на языке высокого уровня (я работаю на Free Pascal).
    Т.е. по-видимому, на Ассемблере и м.б. даже используя что-то вроде быстрых преобразований Фурье.

    Прежде всего, такая задача:
    на входе -- поток вычисленных некоторым способом чисел как неких величин вне зависимости от системы счисления,
    и нужно максимально быстро определить, какая троичная цифра (0,1 или 2)
    будет стоять на k-ой позиции в троичном представлении каждого числа.

    Огромная благодарность тем, кто что-то подскажет, очень нужно!!! :blink:
    Сообщение отредактировано: aelita -
      aelita
      Советую почитать Кнута.

      Храни в байте по 5 разрядов. 3*3*3*3*3=243
      При умножение и сложение используй длинную арифметику. Для получения разряда сначала находишь байт, а потом табличкой раскладываешь байт на разряды.
      Правда div и mod сейчас работают быстро и оптимизировать их не надо.
      Вот только делить на 3 не надо. Надо делить на 3*k,если k=0 делить не надо.
      Сообщение отредактировано: Pavia -
        Спасибо!
        В самом деле, Кнут может что-то подсказать.

        1) Вы имеете в виду, что делить на 3k лучше, чем несколько раз на 3?

        2) Мне все же представляется, что для реального ускорения счета нужно использовать 128-битные вычисления в ассемблере (поскольку 2^128 > 3^80).
        Однако, в ассемблере я полная блондинка (программа нужна для научных вычислений, а я никоим образом не являюсь профи в программировании).

        3) Впрочем, на первом этапе вполне достаточно считать, что на входе подаются 64-битные числа в формате QWord Free Pascal,
        которые надо очень быстро перевести в троичную систему до 3^40. Вероятно, для скорости нужно использовать 64-битную арифметику ассемблера.
        Сообщение отредактировано: aelita -
          Цитата aelita @
          1) Вы имеете в виду, что делить на 3k лучше, чем несколько раз на 3?

          Да. Я как понял тебе нужно всего одно число в к-ой позиции.

          Цитата aelita @
          2) Мне все же представляется, что для реального ускорения счета нужно использовать 128-битные вычисления в ассемблере (поскольку 2^128 > 3^80).
          Однако, в ассемблере я полная блондинка (программа нужна для научных вычислений, а я никоим образом не являюсь профи в программировании).

          Во-первых 128-битные числа сами по себе не дают ускорение. Ускорение даёт параллельная обработка данных.
          Во-вторых 128-битного деления CPU не поддерживает. И если бы поддерживал, то ускорения это бы не дало. Так как деление носит инерционный характер вычисления, то чем длиньше числа тем дольше они делятся.
            Цитата Pavia @
            Правда div и mod сейчас работают быстро и оптимизировать их не надо

            Тем не менее умножение работает почти на порядок быстрее, поэтому трюки с заменой деления на константу умножением на обратную величину никто не отменял (хотя для вычисления остатка это не так эффективно, но все же м.б.заметно быстрее деления)
            Сообщение отредактировано: leo -
              leo
              Цитата leo @
              Тем не менее умножение работает почти на порядок быстрее, поэтому трюки с заменой деления на константу умножением на обратную величину никто не отменял

              А ты проверь ;) Из-за зависимости по данным так как после умножения идёт сдвиг мы имеем, что умножение выполняется не оптимально. Отсюда имеем максимум 5 кратное увеличение. А если учесть что для некоторых делителе ещё требуется увеличение на 1 то прирост всего в 4 раза.
              Но мая практика показывает что оно и до 2 раз не всегда доходит.
              Если в цикле будет условные переходы то увеличении производительности можно забыть.
              Даже проста операция такая как загрузка данных из ОЗУ в регистр может выполнятся дольше деления.
                Цитата Pavia @
                А ты проверь ;) Из-за зависимости по данным так как после умножения идёт сдвиг мы имеем, что умножение выполняется не оптимально

                Причем тут оптимально\не_оптимально? Умножение выполянется с фикс.задержкой (латентностью) - 3 такта на (современных) AMD и 5 на Core (mul-5,imul-3), а 32-битное деление соотв-но до 40 тактов на AMD и до 25-30 на Core. Для вычисления частного и остатка от деления нужно 2 умножения (mul + imul), плюс несколько однотактовых операций (пересылка,сдвиг,вычитание), часть из которых может выполняться одновременно с умножением - в итоге все это дело тянет на (3..5)+1+3+1 = 8..10 тактов
                ExpandedWrap disabled
                  //mov ebx,565592401 //= Trunc(2^37/243)
                  ...
                  mov edi,eax    //+0 если одновременно с mul или пред.операцией
                  mul ebx        //+(3..5) тактов  
                  shr edx,5      //+1 такт
                  mov eax,edx    //+0 одновременно с imul
                  imul edx,243   //+3 такта
                  sub edi,edx    //+1 такт


                Цитата Pavia @
                Но мая практика показывает что оно и до 2 раз не всегда доходит

                Ну, а "до 2 раз" - это разве мало?

                Цитата Pavia @
                Если в цикле будет условные переходы то увеличении производительности можно забыть.
                Даже проста операция такая как загрузка данных из ОЗУ в регистр может выполнятся дольше деления.

                Ну это вообще "из другой оперы"
                  leo
                  Цитата leo @
                  Причем тут оптимально\не_оптимально? Умножение выполянется с фикс.задержкой (латентностью)

                  Есть 2 типа задержек. Latency и throughput. Первую я назвал не оптимальной вторую оптимальной.
                  Latency - задержка до завершения операции.
                  throughput - задержка до того как вычислительный блок можно будет использовать для другой операции

                  Так вот у деления задержка будет браться throughput. А вот если делать через умножение то там будет Latency.
                  Но в целом первое уравновешивает второе. Просто я упоминал про оптимально\не_оптимально чтобы вы правильно такты посчитали.

                  Сейчас залез в Агнера Фога с удивлением узнал, что руководство от intel привирает.
                  Так вот у Агнера Фога результат видимо точнее, он для маленьких чисел указывает результат гораздо меньше
                  Core в зависимости от модели для маленьких чисел
                  модель Latency throughput
                  CORE65 18 12
                  CORE45 9 -
                  Nehalem 11 7

                  Цитата
                  Ну, а "до 2 раз" - это разве мало?
                  Мало много понятие растяжимое.
                  2 раза хорошо, всё что меньше меня печалит. Дольше разбираться надо.

                  Цитата
                  Ну это вообще "из другой оперы"

                  Был у меня выбор добавить mod N в цикл или нет. Для безопасности кода решил добавить mod, а скорость и не изменилась. Относительная точность измерений скорости 10%
                  Сообщение отредактировано: Pavia -
                    Цитата Pavia @
                    Так вот у деления задержка будет браться throughput

                    Это только для независимых операций, а при переводе числа из одной системы счисления в другую, вычисление каждого следующего разряда зависит от предыдущего и соотв-но следующее деление не может начаться пока полностью не завершится предыдущее -> latency в чистом виде

                    Цитата Pavia @
                    Сейчас залез в Агнера Фога с удивлением узнал, что руководство от intel привирает.
                    Так вот у Агнера Фога результат видимо точнее, он для маленьких чисел указывает результат гораздо меньше

                    Не знаю, где ты увидел "гораздо", т.к. в интеловском мане примерно те же цифры (для IDIV r32).
                    Да, за счет фишки с "early exit" деление с малым результатом выполняется быстрее. Но в данной задачке речь идет о работе с "довольно большими -- до 3^80) числами", поэтому при многократных делениях будут встречаться и большие и малые задержки, так что можно расчитывать только на некое среднее значение

                    Добавлено
                    PS: Конечно для частной задачки, когда нужно узнать только одну троичную цифру на фикс.позиции k (т.е. не обязательно раскладывать все число) можно и двумя делениями обойтись (на 3k из таблицы и затем на 3 для получения остатка)
                      Цитата leo @
                      зависит от предыдущего и соотв-но следующее деление не может начаться пока полностью не завершится предыдущее -> latency в чистом виде

                      Так чисел у него много. Можно делить каждое.
                      А если бы было одно то можно, так. Поделить на 3*3*3*3 получим частое и остаток. Их уже двое и их можно поделить на 3*3 что хорошо параллелится и так далее.


                      Цитата leo @
                      Но в данной задачке речь идет о работе с "довольно большими -- до 3^80) числами"

                      И что? Можно ведь взять алгоритм с постоянной скоростью основанный на деление маленькими числами.
                      Сообщение отредактировано: Pavia -
                        Pavia
                        Ладно, убедил ;)
                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                        0 пользователей:


                        Рейтинг@Mail.ru
                        [ Script execution time: 0,0818 ]   [ 15 queries used ]   [ Generated: 27.07.25, 10:57 GMT ]