ความผิดพลาดในอัลกอริทึมการคูณ -O (n lg n) นี้อยู่ที่ไหน


15

บล็อกโพสต์ปริศนาล่าสุดเกี่ยวกับการค้นหาสามช่องว่างเท่า ๆ กันนำฉันไปสู่คำถามสแต็คโอเวอร์โฟลว์พร้อมคำตอบยอดนิยมที่อ้างว่าทำในเวลา O (n lg n) ส่วนที่น่าสนใจคือว่าการแก้ปัญหาที่เกี่ยวข้องกับการ squaring พหุนาม, อ้างอิงกระดาษที่อธิบายถึงวิธีที่จะทำมันใน 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) แต่ค่าใช้จ่ายรวมสำหรับการเพิ่มขึ้นทีละครั้งคือ O (x)
  • อัลกอริทึมการคูณพหุนามเป็นกระดาษผิดหรือมีเงื่อนไขที่ฉันละเมิดหรือไม่? กระดาษใช้การแปลงฟูริเยร์ที่รวดเร็วแทนการแปลงเชิงทฤษฎีจำนวนซึ่งอาจเป็นปัญหา
  • มีคนฉลาดมากมายที่พลาดอัลกอริทึมของSchönhage – Strassen เป็นเวลา 40 ปีหรือไม่ นี่ดูเหมือนจะเป็นไปได้น้อยมาก

ฉันเขียนโค้ดเพื่อใช้งานจริงยกเว้นการคูณพหุนามที่มีประสิทธิภาพ (ฉันยังไม่เข้าใจว่าทฤษฏีการแปลงตัวเลขยังดีพอ) การทดสอบแบบสุ่มปรากฏขึ้นเพื่อยืนยันว่าอัลกอริทึมนั้นถูกต้องดังนั้นปัญหาน่าจะเกิดขึ้นในการวิเคราะห์ความซับซ้อนของเวลา


ตารางไม่ควรรวมอยู่ด้วยx^10 + 2x^8? x ^ 10 เพียงครั้งเดียว (x ^ 5 * x ^ 5) และ x ^ 8 สองครั้ง (x ^ 6 * x ^ 2 + x ^ 2 * x ^ 6)
Sjoerd

ฉันทำตัวอย่างด้วยมือ ฉันทำผิดเลขคณิต ขอโทษ ฉันใช้อัลกอริทึมจริงและทดสอบและได้ผลลัพธ์ที่ถูกต้อง แต่
Craig Gidney

คำตอบ:


13

อัลกอริทึมของคุณคล้ายกับSchönhage – Strassen มาก ในขั้นตอน FFT มีจำนวนมากมีส่วนร่วม - ในขณะที่คุณพูดถึงขนาดของพวกเขาสามารถเป็นได้ถึงn) เลขคณิตของมันไม่ได้มาฟรี คุณต้องใช้การก่อสร้างแบบวนซ้ำและคุณจะสูญเสียบางสิ่งไปO(เข้าสู่ระบบn)


1

"ความผิดพลาด" ที่นี่คือการแปลงฟูริเยร์สามารถคำนวณได้ในขั้นตอน O (n log n) ของการเพิ่มหรือทวีคูณตัวเลขที่จะถูกแปลง แต่เมื่อ n โตขึ้นมากจริง ๆ ตัวเลขที่ถูกแปลงก็ใหญ่ขึ้นเช่นกัน ปัจจัยบันทึกอื่นเข้าสู่ระบบ n

ในทางปฏิบัติฉันคิดว่าการใช้ทศนิยมความแม่นยำสี่เท่า (จุดลอยตัว 128 บิตโดยใช้ค่าสองเท่า) หรือจุดคงที่ 128 บิตใน FFT จะเพียงพอสำหรับผลิตภัณฑ์ใด ๆ ที่มีขนาดเล็กพอที่จะคำนวณได้ทั้งหมด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.