Блог пользователя ardmn

Автор ardmn, 13 лет назад, По-русски
Уважаемые пользователи сайта , пожалуйста поделитесь хорошим классом Длинки(+,-,/,%,*). Свой писал но вроде медленный. Не получается модернизировать. Хорошим в смысле быстрой роботы .
Буду очень благодарен. 
  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
http://shygypsy.com/tools/ (BigInt.cpp)
Если нужно более быстрое *, то можно это http://e-maxx.ru/algo/fft_multiply заюзать еще.

P.S. а какой язык? =)
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    тут по ходу основание системы 10. Если будет 1000000 вроде быстрее должно работать? 
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Для сложеня в 6 раз, для умножения в 36..
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
         мне кажется не совсем, ведь действия над числами по модулю 10 происходят быстрее чем по модулю 10^6
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          это да но ведь не в 6 раз ? ... хотя времени на преобразование тратиться гораздо больше . Как вы думаете это существенно влияет на время работы и как лучше это реализовать? 
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            по модулю 10^4, при большей базе переполнения будут
            • 13 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              откуда переполнения ? если использовать long long 999999*999999 -не будет переполнения :)
              или я вас не понял? 
              • 13 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                если long long - тогда да, можно до 10^9
                а вот из инта 10^5 уже вылазит
              • 13 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                long long использовать можно, но в нем операция взятия по модулю работает феерически медленно.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Я обычно юзаю JAVA для этого но бывает мозгов не хватает написать быстрое решение и приходится кодить на С++.По этому хочу у опытных опросить проверенный временем class  :) 
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Да где ж ты такие задачи встречал, что BigInteger не проходит, а тупое решение с самодельной сишной длинной арифметикой проходит?
    • 13 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится
      Задача «A2+...+B2» с последнего гран-при Удмуртии с Опенкапа. Там такие большие числа, что BigInteger не успевает преобразовать их в двоичную систему счисления. Если реализовать свою арифметику, которая пользуется десятичным основанием для внутреннего представления, то все будет ок. Правда эта задача и без длины нормально решается.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Нам рассказывали на лекциях что для Cnk  лучше как раз написать свой собственный класс чем в явку загонять. Даже если считаешь умнее чем делением одного факториала на два других.
13 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

http://www.everfall.com/paste/id.php?fhelgcbkw1cf

вот весьма эффективная длинка, битовый подход, основание 2^32

многое можно соптимизировать, но это я писал давно и небыло цели особо извращатся.

реализация деления за n^2 * log(base) = n^2 * 32, можно за n^2 реализовать по кнуту, по моим тестам

в 6 или 12 раз быстрее если цифру брать за 8 или 16 бит соответственно

13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
Вот вроде-бы одна из самых быстрых библиотек длинки для с++ но не знаю насколько она применима на контестах.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну а вы попробуйте ее применить и узнаете.
  • 13 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится
    Я тоже не знаю и по этому просил проверенную вещь :) но спасибо ;)
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

со встроенной karatsubaMultiply.
  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    тут через вектор :) не плохо но как я заметил , даже не знаю почему но по ходу вектор дольше работает чем обычный массив ... (кстати интересно почему? если это правдатак )
    • 13 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится +3 Проголосовать: не нравится
      Может быть если не делать много push_back'ов, а выделить сразу памяти сколько надо через resize, то вектор будет работать также быстро как и обычный массив.

      Хотя я хз, сам бы хотел узнать где вектор и в чем проигрывает, если проигрывает.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Есть догадка что при push_back'ах создается еще один вектор на 1 элемент больше, ну и дальше там идет переадресация. Просто кто-то мне рассказал что на операцию push_back() вектор тратит в два раза больше памяти чем нужно. Этот человек так же рассказал что на операцию pop_back() вектор тратит в 4 раза больше чем нужно(интересно, почему). Но если действительно все делать через resize() то время экономится.
        • 13 лет назад, # ^ |
          Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится
          push_back работает так: если выделенной памяти не хватает для очередного элемента, то создается новый вектор в два раза большего размера, куда копируется содержимое старого. Такое удвоение позволяет работать пуш-бэку за амортизированную константу.
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Действительно похоже, но в вашем утверждении ".. в два раза большего размера .." не уверен на 100%
            • 13 лет назад, # ^ |
                Проголосовать: нравится +3 Проголосовать: не нравится
              Это легко проверить:

              #include <stdio.h>

              #include <vector>


              std::vector < int > v;


              int main() {

              for (int i = 0; i < 100; i++) {

              printf("Size and Capacity before push back: %d %d\n", v.size(), v.capacity());

              v.push_back(1);

              printf("Size and Capacity after  push back: %d %d\n", v.size(), v.capacity());

              }

              return 0;

              }


          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Не в два, а в φ ≈ 1.618
            • 13 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              Судя по работе программы, которая написана выше, capacity всегда увеличивается ровно в два раза. Может у вас реализация STL другая.
              • 13 лет назад, # ^ |
                Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
                Если не ошибаюсь, это всё ваша студия шалит.
                Ошибаюсь: в gcc аналогичный результат. Однако, fetertriste по сути прав. ~1.5 - более кошерное значение для памяти и используется в некоторых реализациях.
                • 13 лет назад, # ^ |
                    Проголосовать: нравится 0 Проголосовать: не нравится
                  gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)

                  Какая нафиг студия?)

                  Кстати, что это программа у вас выводит, если не секрет?
              • 13 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                Да, от реализации зависит, конечно. Важно, чтобы было  ≤ φ

                Вот, а оттуда по ссылкам
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Про расширение уже написали.
          Про pop_back в 4 раза больше - если количество элементов в векторе <= capacity/4 - вектор сужают в 2 раза.
          Вообще это классическая реализация саморасширяющегося - самосужающегося массива.
13 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится
Оптимизация ДА зависит от конкретного случая
Можно сделать крайне быструю длинку со следующими эвристиками:
1. использовать 10^k как основание системы счисления, если результат нужен десятичный.
2. использовать кэширование при умножении на короткое.
и т.п.

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

В Харькове на сборах рассказывался алгоритм Карацубы и Быстрое преобразование Фурье. Эти алгоритмы выполняют умножение за NlogN.  При этом как я понял БПФ лучше работает с базой 10, а не 10^9. 

В случае если необходимо реализовать операцию сложения, то стоит избавляться от долгой операции %. Были задачи, когда эта оптимизация спасает. 

Аналогичный случай с умножением за N^2. Необходимо избавиться от %. Дмитрий Жуков говорил, что подобная оптимизация может помочь, даже в том случа если на первый взгляд решение пройти не может.

  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    Карацуба разве не за O(n^1.6)?
    В БПФ с базой 10^9 происходят на больших числах(1000 знаков) какие-то странные то ли переполнения, то ли потери точности. Факт в том что несколько(штук 8-10) последних знаков наверняка неправильна. Не знаю, я где-то лажал или еще что, но если ставить основание поменьше(10^4 , например) - то все ок.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Как я понял БПФ чем меньше база тем лучше. Карацуба, если я  не ошибаюсь,  Nlog1.5N


      • 13 лет назад, # ^ |
          Проголосовать: нравится +1 Проголосовать: не нравится
        Вообще исходная задача размерности N, делится на три задачи размерности в N/2 и они объединяются за N действий, сложность N^log2(3)
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
И ещё у Карацубы большая константа, из-за этого его примень стоит только на больших числах