Đâu là sai lầm trong thuật toán nhân rõ ràng-O (n lg n) này?


15

Một bài đăng trên blog về câu đố gần đây về việc tìm ra ba câu hỏi cách đều nhau dẫn tôi đến một câu hỏi stackoverflow với câu trả lời hàng đầu tuyên bố sẽ thực hiện nó trong thời gian O (n lg n). Phần thú vị là giải pháp liên quan đến bình phương một đa thức, tham khảo một bài viết mô tả cách thực hiện trong thời gian O (n lg n) .

Bây giờ, nhân đa thức thực tế giống như nhân số. Sự khác biệt thực sự duy nhất là thiếu mang. Nhưng ... việc mang cũng có thể được thực hiện trong thời gian O (n lg n). Ví dụ:

    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

Vì vậy, câu hỏi của tôi là: lỗi ở đâu? Nhân số trong O (n lg n) là một vấn đề mở khổng lồ trong khoa học máy tính và tôi thực sự nghi ngờ câu trả lời sẽ đơn giản như vậy.

  • Là mang sai, hay không O (n lg n)? Tôi đã tìm ra rằng lg n + 1 bit trên mỗi giá trị là đủ để theo dõi các giao dịch và thuật toán rất đơn giản Tôi sẽ ngạc nhiên nếu nó sai. Lưu ý rằng, mặc dù gia số riêng lẻ có thể mất thời gian O (lg n), chi phí tổng hợp cho gia số x là O (x).
  • Là thuật toán nhân đa thức từ bài báo sai, hoặc có các điều kiện mà tôi đang vi phạm? Bài viết sử dụng một biến đổi Fourier nhanh thay vì một biến đổi lý thuyết số, có thể là một vấn đề.
  • Có rất nhiều người thông minh đã bỏ lỡ một biến thể rõ ràng của thuật toán Schönhage tại Strassen trong 40 năm? Điều này dường như ít có khả năng.

Tôi thực sự đã viết mã để thực hiện điều này, ngoại trừ phép nhân đa thức hiệu quả (tôi chưa hiểu rõ về biến đổi lý thuyết số đủ). Kiểm tra ngẫu nhiên xuất hiện để xác nhận thuật toán là chính xác, vì vậy vấn đề có thể xảy ra trong phân tích độ phức tạp thời gian.


Không nên hình vuông bao gồm x^10 + 2x^8? x ^ 10 chỉ một lần (x ^ 5 * x ^ 5) và x ^ 8 hai lần (x ^ 6 * x ^ 2 + x ^ 2 * x ^ 6)
Sjoerd

Tôi đã làm ví dụ bằng tay. Tôi đã phạm một lỗi số học. Lấy làm tiếc. Tôi thực sự đã thực hiện thuật toán và kiểm tra nó và nhận được kết quả chính xác.
Craig Gidney

Câu trả lời:



1

"Sai lầm" ở đây là một biến đổi Fourier có thể được tính theo các bước O (n log n) của việc thêm hoặc nhân các số cần chuyển đổi, nhưng khi n phát triển thực sự lớn, các số được chuyển đổi cũng lớn hơn, thêm vào đó một yếu tố khác log log n.

Trong thực tế, tôi nghĩ rằng sử dụng điểm nổi chính xác quad (điểm nổi 128 bit sử dụng hai giá trị kép) hoặc điểm cố định 128 bit trong FFT là đủ cho bất kỳ sản phẩm nào đủ nhỏ để tính toán.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.