อัลกอริทึมรากที่สองจำนวนเต็มความแม่นยำตามอำเภอใจ?


9

มีอัลกอริทึมย่อยที่รู้จักกันดีสำหรับการคำนวณพื้นของสแควร์รูทของnจำนวนเต็มบิตหรือไม่?

อัลกอริธึมไร้เดียงสานั้นจะเป็นอย่างไร

def sqrt(x):
    r = 0
    i = x.bit_length() // 2
    while i >= 0:
        inc = (r << (i+1)) + (1 << (i*2))
        if inc <= x:
            x -= inc
            r += 1 << i
        i -= 1
    return r

สิ่งนี้ต้องใช้O(n)การวนซ้ำแต่ละอันเกี่ยวข้องกับการเพิ่มที่เป็นO(n)เวลาดังนั้นจึงเป็นO(n^2)เวลาโดยรวม มีอะไรเร็วขึ้นไหม ฉันรู้ว่าในกรณีของการคูณมีอัลกอริทึมพิเศษที่ทำได้ดีกว่าเวลากำลังสอง แต่ฉันไม่สามารถหาอะไรสำหรับรากที่สอง


คำตอบของฉันสิ่งที่เกี่ยวข้องอาจช่วยcs.stackexchange.com/a/37338/12052 ปัญหาเพียงอย่างเดียวคือส่วนหนึ่งของสมการที่จำเป็นที่คุณต้องใช้เพื่อค้นหาความแม่นยำ
Francesco Gramano

@FrancescoGramano: ขออภัยฉันไม่คิดว่าจะช่วยได้
Aryabhata

btw ความต้องการย่อยกำลังสองนี้เป็นปัญหาที่ใหญ่กว่าหรือไม่ เพราะความแตกต่างระหว่างสมการกำลังสองง่ายและสมการกำลังสองย่อยที่ซับซ้อนอาจไม่ได้ใหญ่ในทางปฏิบัติ หรือเป็นเพียงความสนใจทางทฤษฎี?
Aryabhata

@Aryabhata ขออภัยฉันไม่เห็นความคิดเห็นของคุณก่อนหน้านี้ ไม่มันไม่ใช่ส่วนหนึ่งของปัญหาที่ใหญ่กว่าเพียงแค่อยากรู้อยากเห็น
พลวง

คำตอบ:


5

คุณสามารถใช้วิธีของนิวตันหรือวิธีอื่น ๆ ในการหาค่าประมาณของรากของพหุนามp(x)=x2c.

อัตราการบรรจบกันของวิธีการของนิวตันจะเป็นกำลังสองซึ่งหมายความว่าจำนวนบิตที่ถูกต้องเป็นสองเท่าในการทำซ้ำแต่ละครั้ง ซึ่งหมายความว่าO(lgn) วนซ้ำของวิธีของนิวตันพอเพียง

การคำนวณซ้ำแต่ละครั้งของวิธีการของนิวตัน

xj+1=xj(xj2c)/(2xj)=0.5xj+c2xj.

ความซับซ้อนของการคูณคือ O (blgb)เพื่อคูณสอง bจำนวนเต็มบิต (ละเว้น lglgbปัจจัย). ความซับซ้อนของบิตสำหรับการหาร (ถึงbบิตของความแม่นยำ) เหมือนกัน ดังนั้นสามารถคำนวณซ้ำแต่ละครั้งได้O (nLGn)การดำเนินงาน คูณด้วยO(LGn) ซ้ำเราพบว่าเวลาทำงานโดยรวมในการคำนวณรากที่สองไป n บิตของความแม่นยำคือ O (n(LGn)2). นี่คือสมการกำลังสอง

ฉันคิดว่าการวิเคราะห์อย่างระมัดระวังยิ่งแสดงให้เห็นว่าสิ่งนี้สามารถปรับปรุงได้ O (nLGn) เวลาทำงาน (โดยคำนึงถึงว่าเราจำเป็นต้องรู้เท่านั้น xJ ภายใน J บิตของความแม่นยำมากกว่า nบิตของความแม่นยำ) อย่างไรก็ตามการวิเคราะห์ขั้นพื้นฐานยิ่งแสดงเวลาในการทำงานที่ชัดเจนมากขึ้นแล้ว


ในหนึ่งไบนารียังมีการคาดเดาเริ่มต้นที่ดีโดยใช้ตัวตน x1/2=21/2log2x. แทนที่จะคำนวณการบันทึกหนึ่งสามารถประมาณlog2x ตามจำนวนตัวเลขใน x. เช่น,log21010116.
Nick Alger

@DW: แต่เราไม่ได้มองหารากที่สองจำนวนเต็ม? หากคุณใช้วิธีการวนซ้ำของนิวตันโดยใช้เลขคณิตเลขจำนวนเต็มเท่านั้นเราจำเป็นต้องมีเหตุผลเพิ่มเติมสำหรับO(logn)อ้างสิทธิ์ใช่มั้ย ไม่อย่างนั้นเรากำลังสันนิษฐานว่ามีความแม่นยำเพียงพอแล้ว ... ขออภัยหากฉันขาดอะไรที่ชัดเจน
Aryabhata

@DW: "อัตราการลู่เข้าสำหรับวิธีของนิวตัน" จะไม่เป็นกำลังสองถ้า =0และฉันไม่รู้ว่าจะเกิดอะไรขึ้นกับค่าของ นั่นไม่ใช่ reals ที่ไม่ใช่เชิงลบ ประมาณการของคุณสำหรับความซับซ้อนบิตของคูณเป็นที่เข้มงวดมากขึ้นกว่าคำพูดของคุณต่อไปนี้แสดงให้เห็น นอกจากนี้เรา "ต้องรู้ด้วย xJ ภายในเกี่ยวกับ " 2J "บิตของความแม่นยำ"

@Aryabhata: เราไม่ได้ค่อนข้าง "มองหารากที่สองจำนวนเต็ม"; เรากำลังมองหา "พื้นของสแควร์รูท" คุณพูดถูกเกี่ยวกับปัญหาเลขคณิตเลขจำนวนเต็มถึงแม้ว่าความซับซ้อนบิตเดียวกันจะเก็บไว้สำหรับการดำเนินการจุดลอยตัว

1
@RickyDemer ใช่ c=0 เป็นกรณีพิเศษเพราะรากของ p(x) มีหลายหลาก 2 แต่เมื่อ c>0รากมีหลายหลาก 1 เพื่อให้วิธีการของนิวตันไม่ได้มีการบรรจบกันสมการกำลังสอง ฉันสมมติว่าไม่มีใครใช้วิธีของ Newton ในการคำนวณสแควร์รูทของc=0(เนื่องจากสแควร์รูทของศูนย์เป็นศูนย์อย่างชัดเจน) ดังนั้นคุณพยายามพูดอะไร ความคิดเห็นของคุณเป็นความคิดเห็นเล็ก ๆ น้อย ๆ ที่แก้ไขได้ด้วยการเพิ่มบางสิ่งลงในคำตอบของฉันที่ระบุว่า "กรณีพิเศษรากที่สองของศูนย์" หรือมีบางสิ่งที่ลึกซึ้งกว่าที่ฉันขาดหายไปหรือไม่
DW

7

หนึ่งในปัญหาของวิธีการของนิวตันคือต้องใช้การดำเนินการหารในแต่ละการวนซ้ำซึ่งเป็นการดำเนินการจำนวนเต็มพื้นฐานที่ช้าที่สุด

อย่างไรก็ตามวิธีการของนิวตันสำหรับสแควร์รูทซึ่งกันและกันกลับทำไม่ได้ ถ้าx คือหมายเลขที่คุณต้องการค้นหา 1xย้ำ:

Rผม+1=12Rผม(3-xRผม2)

สิ่งนี้มักแสดงเป็น:

Wผม=Rผม2
dผม=1-Wผมx
Rผม+1=Rผม+Rผมdผม2

นั่นคือการคูณสามครั้ง การหารด้วยสองสามารถนำไปใช้เป็น shift-right ได้

ตอนนี้ปัญหาคือว่า Rไม่ใช่จำนวนเต็ม อย่างไรก็ตามคุณสามารถจัดการมันได้โดยการใช้ floating-point ด้วยตนเองและดำเนินการ shift หลายอย่างเพื่อชดเชยเมื่อเหมาะสม

ก่อนอื่นเรามาช่วยกัน x:

x'=2-2อีx

ที่เราต้องการ x' จะมากกว่า แต่ใกล้กับ 1. หากเราเรียกใช้อัลกอริทึมด้านบนx' แทน xเราพบว่า R=1x'. จากนั้นx=2อีRx'.

ตอนนี้มาแยกกัน R เป็นแมนทิสซาและเลขชี้กำลัง:

Rผม=2-อีirผม'

ที่ไหน Rผม'เป็นจำนวนเต็ม สังหรณ์ใจอีผม แสดงถึงความแม่นยำของคำตอบ

เรารู้ว่าวิธีการของนิวตันประมาณสองเท่าของจำนวนนัยสำคัญที่แม่นยำ ดังนั้นเราสามารถเลือก:

อีผม+1=2อีผม

ด้วยการจัดการเล็กน้อยเราพบ:

อีผม+1=2อีผม
Wผม=Rผม'2
xผม'=x22อี-อีผม+1
dผม=2อีผม+1-Wผม'xผม'2อีผม+1
Rผม+1'=2อีผมRผม'-Rผม'dผม2อีผม+1

ทุกครั้งที่มีการซ้ำ:

xrix2e+ei

ตัวอย่างเช่นลองคำนวณหาสแควร์รูทของ x=263. เรารู้ว่าคำตอบคือ2312. สแควร์รูทซึ่งกันและกันคือ12231ดังนั้นเราจะตั้งค่า e=31 (นี่คือขนาดของปัญหา) และสำหรับการคาดเดาเริ่มต้นของเราเราจะเลือก r0=3 และ e0=2. (นั่นคือเราเลือก34 สำหรับการประมาณการเบื้องต้นของเราถึง 12.)

แล้ว:

e1=4,r1'=11
อี2=8,R2'=180
อี3=16,R3'=46338
อี4=32,R4'=3037000481

เราสามารถหาเวลาที่จะหยุดซ้ำได้โดยการเปรียบเทียบ อีผม ถึง e; ถ้าฉันคำนวณอย่างถูกต้องei>2eควรจะดีพอ เราจะหยุดที่นี่และค้นหา:

2633037000481×263231+32=3037000481

สแควร์รูทจำนวนเต็มที่ถูกต้องคือ 3037000499ดังนั้นเราค่อนข้างสนิทกัน เราสามารถทำซ้ำอีกครั้งหรือทำซ้ำขั้นสุดท้ายที่เพิ่มประสิทธิภาพซึ่งไม่ได้เป็นสองเท่าei. รายละเอียดจะถูกทิ้งไว้เป็นแบบฝึกหัด

ในการวิเคราะห์ความซับซ้อนของวิธีการนี้ให้สังเกตว่าการคูณสอง bจำนวนเต็มบิตจะใช้เวลา O(blogb)การดำเนินงาน อย่างไรก็ตามเราได้จัดเตรียมสิ่งต่าง ๆ เพื่อให้ri<2ei. ดังนั้นการคูณเพื่อคำนวณwi คูณสอง eiตัวเลขบิตในการผลิต ei+1- จำนวนบิตและอีกสองคูณสองคูณสอง ei+1ตัวเลขบิตในการผลิต 2ei+1หมายเลขบิต

ในแต่ละกรณีจำนวนการดำเนินการต่อการทำซ้ำคือ O(eilogei)และมี O(loge)จำเป็นต้องทำซ้ำ การคูณสุดท้ายคือตามลำดับของO(2elog2e)การดำเนินงาน ดังนั้นความซับซ้อนโดยรวมก็คือO(elog2e) การดำเนินงานซึ่งเป็นกำลังสองย่อยในจำนวนบิตใน x. ที่ทำเครื่องหมายในช่องทั้งหมด

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

เป็นการสังเกตครั้งสุดท้ายการคูณสองครั้งเป็นแบบฟอร์ม ab2c. เห็นได้ชัดว่ามันเป็นการสิ้นเปลืองในการคำนวณบิตทั้งหมดของab โยนเท่านั้น cของพวกเขาออกไปพร้อมกับกะ - ขวา การใช้วิธีการคูณแบบชาญฉลาดซึ่งคำนึงถึงสิ่งนี้ยังถือว่าเป็นแบบฝึกหัด


นี่คือสิ่งที่ดี หนึ่งความคิดเห็น แต่: ความซับซ้อนของการแบ่งบิต asymptotically ประมาณไม่เหมือนกับความซับซ้อนบิตของการคูณ? คุณกำลังพูดถึงบางสิ่งบางอย่างที่ให้การปรับปรุงปัจจัยคงที่ไม่ใช่การปรับปรุงเชิงซีมใช่มั้ย ไม่ชัดเจนจากคำตอบของคุณ
DW

คุณบอกว่าคูณสอง bจำนวนเต็มบิตจะใช้เวลา O(blgb)การดำเนินงานบิต ฉันคิดว่าคำตอบที่ถูกต้องเป็นเหมือนO(blgb(lglgb)O(1))(ขวา?). คุณอาจต้องการระบุว่าคุณไม่สนใจปัจจัยบันทึกการทำงานของโพลีบันทึก (เช่นโดยใส่เครื่องหมายตัวหนอนทับ O ใหญ่ของคุณหรือบางอย่าง)
DW

1
@DW: ไม่เขาบอกว่า "คูณสอง จำนวนเต็มบิตจะใช้เวลา O(เข้าสู่ระบบ) การดำเนินงาน." คำว่า "บิต" จะปรากฏเพียงครั้งเดียวเท่านั้น มิฉะนั้นฉันก็จะชี้ให้เห็นแล้วว่า

มันเป็นเรื่องของปัจจัยคงที่ใช่ อัลกอริธึมการแบ่งจำนวนเต็มขนาดใหญ่ที่ดีที่สุดใช้เทคนิคคล้ายกับอัลกอริธึมทั้งหมดเช่นการวนซ้ำของนิวตัน - ราฟสันและการเพิ่มความแม่นยำที่มีประสิทธิภาพในการทำซ้ำแต่ละครั้ง การวนนิวตัน - ราฟสันภายในเสาวนนิวตัน - ราฟสันบนปัจจัยคงที่! Ricky Demer ถูกต้อง; ฉันคิดในรูปแบบคำว่า RAM ฉันน่าจะพูดถึงสิ่งนี้
นามแฝง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.