Де помилка в цьому, очевидно, O (n lg n) алгоритмі множення?


15

Нещодавнє повідомлення про блог із головоломки про пошук трьох рівномірно розміщених запитань привело мене до питання про стаковий перебіг із найвищою відповіддю, яка стверджує, що це потрібно зробити в O (n lg n). Цікава частина полягає в тому, що рішення включає в себе квадратичний поліном, посилання на документ, який описує, як це зробити за O (n lg n) час .

Тепер множення многочленів практично те саме, що множення чисел. Єдина реальна відмінність - відсутність носіїв. Але ... перенесення також може бути зроблено в O (n lg n) час. Наприклад:

    var value = 100; // = 0b1100100

    var inputBitCount = value.BitCount(); // 7 (because 2^7 > 100 >= 2^6)
    var n = inputBitCount * 2; // 14
    var lgn = n.BitCount(); // 4 (because 2^4 > 14 => 2^3)
    var c = lgn + 1; //5; enough space for 2n carries without overflowing

    // do apparently O(n log n) polynomial multiplication
    var p = ToPolynomialWhereBitsAreCoefficients(value); // x^6 + x^5 + x^2
    var p2 = SquarePolynomialInNLogNUsingFFT(p); // x^12 + 2x^11 + 2x^10 + x^8 + 2x^7 + x^4
    var s = CoefficientsOfPolynomial(p2); // [0,0,0,0,1,0,0,2,1,0,2,2,1]
    // note: s takes O(n lg n) space to store (each value requires at most c-1 bits)

    // propagate carries in O(n c) = O(n lg n) time
    for (var i = 0; i < n; i++)
        for (var j = 1; j < c; j++)
            if (s[i].Bit(j))
                s[i + j].IncrementInPlace();

    // extract bits of result (in little endian order)
    var r = new bool[n];
    for (var i = 0; i < n; i++)
        r[i] = s[i].Bit(0);

    // r encodes 0b10011100010000 = 10000

Тож моє запитання таке: де помилка тут? Множення чисел на O (n lg n) - це гігантська відкрита проблема в інформатиці, і я дійсно дуже сумніваюся, що відповідь була б такою простою.

  • Неправильне перенесення чи ні, O (n lg n)? Я розробив, що lg n + 1 біт на значення достатньо для відстеження переносів, і алгоритм настільки простий, я був би здивований, якщо він був неправильним. Зауважимо, що, хоча окремий приріст може зайняти час O (lg n), сукупна вартість для приросту x становить O (x).
  • Чи неправильний алгоритм множення поліномів з паперу, чи є умови, які я порушую? У статті використовується швидке перетворення фур'є замість теоретичного перетворення числа, яке може бути проблемою.
  • Чи багато розумних людей пропустили очевидний варіант алгоритму Шенхаге – Штрассена протягом 40 років? Це здається найменш вірогідним.

Я фактично написав код, щоб реалізувати це, за винятком ефективного множення поліномів (я ще не добре розумію теоретичне перетворення чисел). Випадкове тестування виявляється для підтвердження правильності алгоритму, тому проблема, ймовірно, в аналізі складності часу.


Чи не повинна включати квадрат x^10 + 2x^8? x ^ 10 лише один раз (x ^ 5 * x ^ 5), і x ^ 8 двічі (x ^ 6 * x ^ 2 + x ^ 2 * x ^ 6)
Sjoerd

Я робив приклад вручну. Я допустив арифметичну помилку. Вибачте. Я фактично реалізував алгоритм і протестував його, і отримав правильні результати.
Крейг Гідні

Відповіді:



1

"Помилка" тут полягає в тому, що перетворення Фур'є можна обчислити на етапах O (n log n) додавання чи множення чисел, які перетворюються, але, оскільки n росте дійсно великими, також збільшуються числа, що перетворюються, що додає інший журнал журналу факторів n.

На практиці я вважаю, що використання плаваючої точки з квадроточною точністю (128-бітова плаваюча точка з використанням двох подвійних значень) або 128-бітної фіксованої точки в FFT буде достатньо для будь-якого продукту, який є досить малим, щоб його можна було взагалі розрахувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.