คณิตศาสตร์พื้นฐานได้รับการประเมินอย่างมีประสิทธิภาพโดยภาษาโปรแกรมอย่างไร


22

เมื่อฉันมีส่วนร่วมมากขึ้นกับทฤษฎีที่อยู่เบื้องหลังการเขียนโปรแกรมฉันพบว่าตัวเองหลงใหลและงงงวยจากสิ่งที่ดูเหมือนง่าย .. ฉันรู้ว่าความเข้าใจของฉันเกี่ยวกับกระบวนการพื้นฐานส่วนใหญ่ได้รับการพิสูจน์ด้วยตรรกะวงกลม

ถาม : มันทำงานอย่างไร

A :เพราะมันทำ!

ฉันเกลียดการรับรู้นี้! ฉันรักความรู้และยิ่งไปกว่านั้นฉันรักการเรียนรู้ซึ่งทำให้ฉันมีคำถาม (แม้ว่ามันจะเป็นวงกว้าง)

คำถาม:

ผู้ประกอบการทางคณิตศาสตร์ขั้นพื้นฐานประเมินด้วยภาษาการเขียนโปรแกรมอย่างไร

วิธีการปัจจุบันได้รับการปรับปรุงอย่างไร

ตัวอย่าง

var = 5 * 5; 

การตีความของฉัน:

$num1 = 5; $num2 = 5; $num3 = 0;
while ($num2 > 0) {
    $num3 = $num3 + $num1;
    $num2 = $num2 - 1;
}
echo $num3;

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

var = 5 / 5;

มันทำยังไงดี? ฉันไม่สามารถคิดวิธีแยก 5 เป็น 5 ส่วนเท่า ๆ กันอย่างแท้จริง

var = 5 ^ 5; 

การวนซ้ำของการบวก? การตีความของฉัน:

$base = 5;
$mod = 5;
$num1 = $base;
while ($mod > 1) {

    $num2 = 5; $num3 = 0;
    while ($num2 > 0) {
        $num3 = $num3 + $num1;
        $num2 = $num2 - 1;
    }
    $num1 = $num3;
    $mod -=1;
}
echo $num3;

อีกครั้งนี่เป็นสิ่งที่ไม่มีประสิทธิภาพอย่างมาก แต่ฉันก็ไม่สามารถคิดวิธีอื่นในการทำเช่นนี้ คำถามเดียวกันนี้รวมถึงฟังก์ชั่นที่เกี่ยวข้องกับคณิตศาสตร์ทั้งหมดที่จัดการโดยอัตโนมัติ


1
backstory เล็กน้อยสำหรับฉันฉันกำลังมุ่งหน้าไปที่วิทยาลัยสำหรับวิทยาการคอมพิวเตอร์และต่อมาในทฤษฎีคณิตศาสตร์ในชีวิตเช่นเดียวกับปรัชญาและฟิสิกส์ทฤษฎี แรงบันดาลใจมากมายเวลาน้อย
Korvin Szanto

10
มันปลอดภัยที่จะเข้าใจคุณได้มองไปที่การเชื่อมโยงทั้งหมดจากen.wikipedia.org/wiki/Category:Computer_arithmetic ?
JB King

2
โดยพื้นฐานแล้วมันคล้ายกับวิธีที่คุณถูกสอนให้ทำการคูณหลายหลักและการหารระยะยาวในโรงเรียนประถม ใช้หนึ่งหลักของ A คูณด้วย B. Shift สิบ ใช้ตัวเลขถัดไปของ A คูณด้วย B ทำซ้ำสำหรับตัวเลขทั้งหมดรวมเข้าด้วยกัน เพราะมันเป็นเลขฐานสองการคูณหลักเดียวง่ายกว่า (มันคือ x0 หรือ x1) และแทนที่จะเป็นสิบคุณก็จะเพิ่มเป็นสองเท่า กองมีลักษณะคล้ายกัน
ถามเกี่ยวกับโมนิก้า

คำตอบ:


35

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

ใน 6502 แทบทุกการคำนวณทางคณิตศาสตร์จะทำในการลงทะเบียนที่เรียกว่า Accumulator (การลงทะเบียนเป็นตำแหน่งหน่วยความจำพิเศษภายในโปรเซสเซอร์ที่สามารถเข้าถึงได้อย่างรวดเร็ว) ดังนั้นเมื่อต้องการเพิ่มตัวเลขสองตัวคุณจะต้องป้อนหมายเลขแรกลงใน Accumulator จากนั้นเพิ่มหมายเลขที่สองลงไป

แต่นั่นเป็นเรื่องง่าย เนื่องจาก 6502 เป็นตัวประมวลผล 8 บิตจึงสามารถจัดการตัวเลขได้ตั้งแต่ 0 ถึง 255 เท่านั้นโดยส่วนใหญ่คุณจะต้องการทำงานกับตัวเลขที่มากขึ้น คุณต้องเพิ่มสิ่งเหล่านี้เป็นชิ้น ๆ ละ 8 บิต โปรเซสเซอร์มีแฟล็ก Carry ที่ตั้งค่าไว้เมื่อผลลัพธ์ของการเพิ่มตัวเลขสองจำนวนล้นโอเวอร์ Accumulator หน่วยประมวลผลเสริมว่าในเมื่อทำการเพิ่มดังนั้นจึงสามารถใช้ในการ "ดำเนินการ 1" สมมติว่าคุณเริ่มต้นด้วยไบต์ลำดับต่ำสุดของตัวเลข การเพิ่มแบบหลายไบต์บน 6502 มีลักษณะดังนี้:

  1. ล้างพกธง (CLC)
  2. โหลดไบต์ต่ำสุดของหมายเลขแรก (LDA, ตัวสะสมโหลด)
  3. เพิ่มไบต์ต่ำสุดของจำนวนที่สอง (ADC เพิ่มด้วยการพกพา)
  4. จัดเก็บไบต์ต่ำสุดของผลลัพธ์ (STA, Store accumulator)
  5. ทำซ้ำขั้นตอนที่ 2-4 โดยมีลำดับไบต์ที่สูงขึ้นอย่างต่อเนื่อง
  6. หากในตอนท้ายการตั้งค่าพกพาคุณล้นแล้ว ดำเนินการที่เหมาะสมเช่นการสร้างข้อความแสดงข้อผิดพลาด (BCS / BCC, สาขาถ้าพกชุด / ล้าง)

การลบจะคล้ายกันยกเว้นคุณตั้งค่าการพกพาครั้งแรกใช้คำสั่ง SBC แทนการใช้ ADC และในตอนท้ายการพกพาจะชัดเจนหากมีการไหลออกน้อยเกินไป

แต่เดี๋ยวก่อน! แล้วตัวเลขลบล่ะ? ด้วย 6502 สิ่งเหล่านี้จะถูกจัดเก็บในรูปแบบที่เรียกว่าส่วนประกอบสองอย่าง สมมติว่าตัวเลข 8 บิต -1 ถูกจัดเก็บเป็น 255 เพราะเมื่อคุณเพิ่ม 255 เข้ากับบางอย่างคุณจะได้รับน้อยลงหนึ่งใน Accumulator (บวกกับที่พกติดตัว) -2 ถูกเก็บไว้ที่ 254 และต่อไปจนถึง -128 ซึ่งถูกเก็บไว้ที่ 128 ดังนั้นสำหรับจำนวนเต็มที่ลงนามครึ่งช่วง 0-255 ของไบต์จะใช้สำหรับตัวเลขบวกและครึ่งหนึ่งสำหรับจำนวนลบ (การประชุมนี้ให้คุณตรวจสอบตัวเลขจำนวนเล็กน้อยเพื่อดูว่าเป็นลบหรือไม่)

คิดว่ามันเหมือนนาฬิกา 24 ชั่วโมง: การเพิ่ม 23 ให้กับเวลาจะทำให้เวลาหนึ่งชั่วโมงก่อนหน้านี้ (ในวันถัดไป) ดังนั้น 23 จึงเท่ากับโมดุลของนาฬิกาเป็น -1

เมื่อคุณใช้มากกว่า 1 ไบต์คุณจะต้องใช้ตัวเลขจำนวนมากขึ้นเพื่อลบ ตัวอย่างเช่นจำนวนเต็ม 16 บิตมีช่วง 0-65536 ดังนั้น 65535 จะถูกใช้เพื่อเป็นตัวแทนของ -1 และอื่น ๆ เพราะการเพิ่ม 65535 ไปยังจำนวนใด ๆ ในผลลัพธ์ที่น้อยกว่าหนึ่ง (บวกพกพา)

ใน 6502 มีการดำเนินการทางคณิตศาสตร์เพียงสี่รายการ: เพิ่มลบคูณด้วยสอง (เลื่อนไปทางซ้าย) และหารด้วยสอง (เลื่อนไปทางขวา) การคูณและการหารสามารถทำได้โดยใช้การดำเนินการเหล่านี้เท่านั้นเมื่อจัดการในไบนารี ตัวอย่างเช่นลองคูณ 5 (ไบนารี 101) และ 3 (ไบนารี 11) เช่นเดียวกับการคูณทศนิยมแบบยาวเราเริ่มต้นด้วยตัวเลขหลักที่ถูกต้องของตัวคูณและทวีคูณ 101 คูณ 1 ให้ 101 แล้วเราเลื่อนซ้ายและตัวคูณคูณกับ 1010 คูณ 1 ให้ 1010 แล้วเราเพิ่มผลลัพธ์เหล่านี้เข้าด้วยกันให้ 1111 หรือ 15. เนื่องจากเราคูณด้วย 1 หรือ 0 เท่านั้นเราจึงไม่คูณจริงๆ ตัวคูณแต่ละตัวเพียงทำหน้าที่เป็นธงซึ่งบอกให้เราทราบว่าจะเพิ่มตัวคูณ (เลื่อน) หรือไม่

Division นั้นคล้ายคลึงกับการหารยาวแบบแมนนวลโดยใช้ตัวหารทดลองยกเว้นในไบนารี หากคุณหารด้วยค่าคงที่มันเป็นไปได้ที่จะทำสิ่งนี้ในลักษณะที่คล้ายคลึงกับการลบ: แทนที่จะหารด้วย X คุณจะคูณด้วยการเรนเดอร์ 1 / X ที่ทำให้เกิดผลลัพธ์ที่ต้องการบวกกับการล้น แม้วันนี้จะเร็วกว่าการหาร

ตอนนี้ลองทำเลขทศนิยมในแอสเซมบลีหรือแปลงตัวเลขทศนิยมเป็นฟอร์แมทเอาท์พุทที่ดีในชุดประกอบ และจำไว้ว่ามันคือปี 1979 และความเร็วสัญญาณนาฬิกาคือ 1 MHz ดังนั้นคุณต้องทำอย่างมีประสิทธิภาพมากที่สุด

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


3
สวัสดีขอบคุณสำหรับคำอธิบายโดยละเอียดของคุณ! มันเป็นสิ่งที่ฉันต้องการ! เมื่ออยู่ในระดับของฉันคุณมักจะลืมว่าสิ่งที่สนับสนุนคุณนั้นซับซ้อนกว่าสิ่งที่คุณทำอยู่ นั่นคือเหตุผลที่แน่นอนว่าทำไมฉันถึงต้องการเรียนวิทยาศาสตร์คอมพิวเตอร์ ฉันเกลียดความจริงที่ว่าถ้าฉันต้องย้อนเวลากลับไปฉันไม่รู้ว่าโลกกำลังเปลี่ยนแปลงไปอย่างไรวิธีกำหนดงบ SQL ที่เหมาะสม;) ไม่ว่าจะด้วยเหตุผลใดก็ตามขอบคุณมากที่ใช้เวลาเขียนคำตอบนี้ คุณให้ฉันทดสอบรสชาติในสิ่งที่ฉันกำลังจะเจาะลึก
Korvin Szanto

7
ไม่เห็นด้วยแอสเซมบลียังคงสูงเกินไปถ้าคุณต้องการทราบว่าคอมพิวเตอร์ทำคณิตศาสตร์คุณต้องดูฮาร์ดแวร์หรืออัลกอริทึมฮาร์ดแวร์อย่างน้อย
jk

เอ๊ะ เมื่อคุณรู้ว่ามีตัวเพิ่มและจำแลงมันเป็นเรื่องง่ายที่จะจินตนาการว่าพวกเขาควบคุมโดยฮาร์ดแวร์เช่นเดียวกับซอฟต์แวร์และมันง่ายต่อการเล่นกับซอฟต์แวร์
kindall

4
-1 ฮาร์ดแวร์ทวีคูณยังไม่ได้ทำกับกะและเพิ่มมาเกือบ 3 ทศวรรษแล้วและซีพียูจำนวนมากสามารถคูณในรอบเดียวได้ ตรวจสอบบทความ Wikipedia เกี่ยวBinary Multiplierกับรายละเอียด
Mason Wheeler

24

ในท้ายที่สุดการดำเนินการทางคณิตศาสตร์ขั้นพื้นฐานจะทำในฮาร์ดแวร์ โดยเฉพาะอย่างยิ่งใน CPU (หรือจริง ๆ แล้วส่วนย่อยของมัน)

มันคือวงจรอิเล็กทรอนิกส์ ตั้งค่าบิตที่เหมาะสมเป็นอินพุตและคุณจะได้รับบิตที่เหมาะสมเป็นเอาต์พุต มันเป็นการรวมกันของประตูตรรกะขั้นพื้นฐาน

http://en.wikipedia.org/wiki/Adder_%28electronics%29

http://en.wikipedia.org/wiki/Binary_multiplier


3
อัลกอริทึมสำหรับฮาร์ดแวร์มีการระบุอย่างระมัดระวังและสามารถศึกษาแยกจากฮาร์ดแวร์
S.Lott

@ S.Lott: ฉันพบว่าความคิดเห็นของคุณสับสน สำหรับฉันอัลกอริทึมเกี่ยวข้องกับชุดของขั้นตอนที่คุณทำตามขั้นตอนสิ่งที่คุณสามารถตั้งโปรแกรมได้ ที่นี่เรากำลังพูดถึงวงจรอิเล็กทรอนิกส์ที่ดำเนินการทางคณิตศาสตร์ขั้นพื้นฐาน ในคำอื่น ๆ เพียงลำดับของประตูที่กระแสปัจจุบัน ดังนั้นจึงเป็น "ตรรกะ" มากกว่า "อัลกอริทึม" ที่ดีที่สุด ... 2 เซนต์ของฉัน
dagnelies

6
อัลกอริทึมคือ "จำกัด แน่นอนและมีประสิทธิภาพ" สามารถอยู่ในวงจรหรือทำด้วยกระดาษและดินสอหรือทำได้ด้วย Tinkertoys หรือโมเลกุลในจานหรือดีเอ็นเอ อัลกอริทึมสามารถเป็นอะไรก็ได้ วงจรอิเล็กทรอนิกส์จะต้องทำตามขั้นตอนวิธีที่กำหนดไว้ มันไม่ได้ผ่านความต้องการอัลกอริทึมอย่างน่าอัศจรรย์
S.Lott

1
กระบวนการที่มีเพียงขั้นตอนเดียวจะถือว่าเป็น "อัลกอริทึม" หรือไม่ FWIW วงจรอิเล็กทรอนิกส์โดยทั่วไปตามตารางความจริง - การประมวลผลขั้นตอนเดียว การที่ตารางความจริงกลายเป็น "รวบรวม" เข้าไปในประตูหลายชั้นไม่ได้คัดค้านความจริงที่ว่ามันเป็นกระบวนการขั้นตอนเดียว
slebetman

2
@ S.Lott: ความคิดเห็นแรกที่เหมาะสมกว่าคือ: "ตรรกะ" ของฮาร์ดแวร์มีการระบุอย่างระมัดระวังและสามารถศึกษาแยกต่างหากจากฮาร์ดแวร์ และแน่นอนมันเป็น การศึกษาของตรรกะเลขฐานสองเรียกว่าพีชคณิตแบบบูล
slebetman

6

ทั้งหมดนี้ถูกปกคลุมด้วยความอดทนอย่างถี่ถ้วนในศิลปะการเขียนโปรแกรมคอมพิวเตอร์ของ Don Knuth

อัลกอริธึมที่มีประสิทธิภาพสำหรับการเพิ่มการลบการคูณและการหารทั้งหมดถูกอธิบายในรายละเอียดที่สมบูรณ์

คุณสามารถอ่านสิ่งต่าง ๆ เช่นนี้ซึ่งครอบคลุมการแบ่งอย่างชัดเจน

http://research.microsoft.com/pubs/151917/divmodnote.pdf


5

มันทำใน picoseconds โดยวงจรอิเล็กทรอนิกส์ 'ตัวคูณฮาร์ดแวร์' ของ Google เป็นต้นสำหรับรายละเอียด ซีพียูสมัยใหม่เป็นผลที่ซับซ้อนอย่างมากจากการปรับปรุงอย่างต่อเนื่องหลายทศวรรษ

BTW เนื่องจากคุณไม่คูณด้วยการเพิ่มซ้ำทำไมคุณถึงนึกว่าคอมพิวเตอร์จะ


คำถามของฉันเกี่ยวกับการใช้เหตุผลเบื้องหลังฟังก์ชั่นมากกว่าฟังก์ชั่นของตัวเองฉันเข้าใจว่ามันตีความโดยโปรเซสเซอร์ฉันอยากรู้ว่า ทฤษฎีที่อยู่เบื้องหลังมันโดยเฉพาะและวิธีที่มันสามารถทำซ้ำในรหัสหลอก
Korvin Szanto

1
การคูณในหัวของฉันคือความทรงจำ การคูณยาวต้องใช้การวนซ้ำในวิธีที่ฉันทำ ฉันจะไปข้างหน้าและโยนฟังก์ชั่นการคูณยาว
Korvin Szanto

2
@Korvin หนังสือที่ฉันแนะนำจะให้บริการคุณได้ดีหากคุณสนใจ ฉันยังแนะนำ "โครงสร้างและการตีความโปรแกรมคอมพิวเตอร์" โดย Harold Abelson และ Gerald Jay Sussman มันเกี่ยวกับคำถามเหล่านี้ในเชิงลึก
Jonathan Henson

คอมพิวเตอร์รุ่นแรกหลายเครื่องรองรับการเพิ่มและการลบเท่านั้น การลบบางอย่างที่สนับสนุนเท่านั้น! ดังนั้นการดำเนินการ x = y * z จึงถูกนำไปใช้เช่นเดียวกับ (z คูณ) {x + y} ในทำนองเดียวกันการแบ่ง x = y / z ถูกนำมาใช้ในขณะที่ (y> z) {x + 1; y = y - z}
James Anderson

@James: พวกเขาสนับสนุนการเปลี่ยนแปลงหรือไม่ ฉันคาดหวังว่าการคูณจะทำได้ผ่านการเลื่อนและเพิ่มในขณะที่การแบ่งคือการเปลี่ยนแปลงการเปรียบเทียบการลบ
วินไคลน์

4

นี่ไม่ได้หมายความว่าจะเป็นคำตอบที่ละเอียดถี่ถ้วนไม่ว่าจะด้วยวิธีใดก็ตาม แต่ควรให้ความคิดกับคุณว่าจะนำสิ่งต่าง ๆ ไปใช้อย่างไร อย่างที่คุณอาจรู้ว่าตัวเลขนั้นแสดงเป็นเลขฐานสอง ตัวอย่างเช่นคอมพิวเตอร์สามารถแสดงหมายเลข 5 เป็น 00000101 การดำเนินการขั้นพื้นฐานที่คอมพิวเตอร์สามารถทำได้คือเลื่อนไปทางซ้ายซึ่งจะให้ 00001010 ซึ่งเป็นทศนิยม 10 หากเป็นตัวเปลี่ยนสองครั้งจะเป็น 00010100 (ทศนิยม 20) ทุกครั้งที่เราเปลี่ยนตัวเลขที่เหลือ 1 ครั้งเราจะเพิ่มจำนวนเป็นสองเท่า ว่าฉันมีตัวเลข x และฉันต้องการคูณมันด้วย 17 ฉันสามารถเลื่อน x ไปทางซ้าย 4 ครั้งแล้วเพิ่ม x ไปยังผลลัพธ์ (16x + x = 17x) นี่จะเป็นวิธีที่มีประสิทธิภาพในการคูณจำนวน 17 ด้วยวิธีนี้จะช่วยให้คุณเข้าใจว่าคอมพิวเตอร์สามารถคูณจำนวนมากได้อย่างไรโดยไม่ต้องใช้การเติมซ้ำ

การหารสามารถใช้การรวมการบวกการลบการเลื่อนขวาเลื่อนไปทางซ้าย ฯลฯ นอกจากนี้ยังมีเทคนิคมากมายสำหรับการเพิ่มตัวเลขให้เป็นเลขชี้กำลัง


เพื่อให้ชัดเจนโดยทั่วไปคุณสามารถเลื่อนครั้งละมากกว่าหนึ่งบิต ดังนั้นผู้ที่ 4 shl r0, 4การดำเนินงานเปลี่ยนแปลงเป็นจริงเพียงหนึ่งในการดำเนินงานที่ต้องการ:
คาเลบ

4

เมื่อฉันยังเป็นเด็กฉันเรียนรู้วิธีการคูณและหารด้วยปากกาและกระดาษโดยไม่ต้องเสียเวลากับการเพิ่มมากเกินไป ต่อมาฉันเรียนรู้ว่ารากที่สองนั้นสามารถคำนวณได้เช่นกัน

ที่มหาวิทยาลัยฉันได้เรียนรู้วิธีการคำนวณตรีโกณมิติและลอการิทึมการดำเนินการด้วยการคูณการหารและการเพิ่มเติม พวกเขาเรียกมันว่าชุดเทย์เลอร์

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

หน่วยจำนวนเต็มหน่วยจุดลอยตัว GPU และ DSP เพียงใช้เทคนิคเก่าทั้งหมดเหล่านั้นบนซิลิคอน


3

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

ประการแรกขอคำถามโดยตรงจากวิธี: ภาษาการเขียนโปรแกรมมีประสิทธิภาพในการประเมินการคูณและการเพิ่มเติมได้อย่างไร คำตอบนั้นง่ายพวกเขารวบรวมพวกเขาเป็นทวีคูณและเพิ่มคำแนะนำ ตัวอย่างเช่นรหัสต่อไปนี้:

a = 1 + 1;
b = a * 20;

เรียบเรียงเป็นบางสิ่งเช่น:

ADD 1 1  a
MUL a 20 b

(โปรดทราบว่าชุดประกอบด้านบนมีไว้สำหรับซีพียูจินตภาพที่ไม่มีอยู่จริงเพื่อความเรียบง่าย)

ณ จุดนี้คุณรู้ว่าคำตอบข้างต้นเพียงแค่เปลี่ยนปัญหาและแก้ปัญหาด้วยเวทมนตร์ฮาร์ดแวร์ คำถามการติดตามเห็นได้ชัดว่าฮาร์ดแวร์เวทย์นั้นทำงานอย่างไร?

ให้ดูที่ปัญหาง่ายกว่าก่อน: นอกจากนี้

ครั้งแรกที่เราทำปัญหาที่คุ้นเคยเพิ่มหมายเลขฐาน 10 ตามปกติ:

 17
+28

ขั้นตอนแรกคือการบวก 7 และ 8 แต่ผลลัพธ์นี้ใน 15 ซึ่งมากกว่าหลักเดียว ดังนั้นเราจึงนำ 1:

(1)
 17
+28
= 5

ตอนนี้เราเพิ่ม 1, 1 และ 2 เข้าด้วยกัน:

 17
+28
=45

ดังนั้นจากนี้เราจะได้รับกฎต่อไปนี้:

  1. เมื่อผลลัพธ์ของการเพิ่มมีมากกว่าหนึ่งหลักเราจะเก็บเลขนัยสำคัญน้อยที่สุดและส่งต่อตัวเลขที่สำคัญที่สุดไปข้างหน้า

  2. หากเรามีตัวเลขที่ถูกส่งต่อไปยังคอลัมน์ของเราเราจะเพิ่มเข้าไปพร้อมกับตัวเลขที่เราเพิ่มเข้าไป

ตอนนี้ได้เวลาตีความกฎข้างต้นในฐาน 2 - พีชคณิตแบบบูลแล้ว

ดังนั้นในพีชคณิตแบบบูลเพิ่ม 0 และ 1 เข้าด้วยกัน = 1 เพิ่ม 0 และ 0 = 0 และเพิ่ม 1 และ 1 = 10 ซึ่งเป็นตัวเลขมากกว่าหนึ่งหลักดังนั้นเราจึงดำเนินการไปข้างหน้า 1

จากนี้เราสามารถสร้างตารางความจริง:

a b  |  sum  carry
-------------------
0 0  |   0     0
0 1  |   1     0
1 0  |   1     0
1 1  |   0     1

จากนี้เราสามารถสร้างสองวงจร / สมการบูลีน - หนึ่งสำหรับการส่งออกของผลรวมและอีกหนึ่งสำหรับการส่งออกของการดำเนินการ วิธีที่ไร้เดียงสาที่สุดคือการใส่รายการอินพุตทั้งหมด ตารางความจริงใด ๆ ไม่ว่าจะใหญ่และซับซ้อนเพียงใดที่สามารถเรียกคืนได้ในรูปแบบนี้:

(AND inputs in first row) OR (AND of inputs in second row) OR ...

นี่เป็นผลรวมของรูปแบบผลิตภัณฑ์ เราดูเฉพาะผลลัพธ์ที่ส่งผลให้ 1 และละเว้น 0s:

sum = (NOT a AND b) OR (a AND NOT b)

ลองเปลี่ยนสัญลักษณ์ภาษาและการเขียนโปรแกรมเพื่อให้ง่ายต่อการอ่าน:

sum = (!a & b) | (a & !b)

โดยพื้นฐานแล้วเราได้แปลงตารางดังนี้:

a b  |  sum  equation
-------------------
0 0  |   0   
0 1  |   1   (!a & b)
1 0  |   1   (a & !b)
1 1  |   0   

สิ่งนี้สามารถนำมาใช้โดยตรงเป็นวงจร:

                _____
 a ------------|     |
    \          | AND |-.     ____
     \  ,-NOT--|_____|  \   |    |
      \/                 `--| OR |----- sum
      /\        _____    ,--|____|
     /  `-NOT--|     |  /
    /          | AND |-`
 b ------------|_____|

ณ จุดนี้ผู้อ่านที่สังเกตจะสังเกตเห็นว่าตรรกะข้างต้นสามารถนำไปใช้เป็นประตูเดียว - ประตู XOR ซึ่งมีพฤติกรรมที่ต้องการโดยตารางความจริงของเรา:

                _____
 a ------------|     |
               | XOR |---- sum
 b ------------|_____|

แต่ถ้าฮาร์ดแวร์ของคุณไม่มีประตู XOR ให้คุณขั้นตอนข้างต้นเป็นวิธีการกำหนดและนำไปใช้ในแง่ของ AND, OR และ NOT เกต

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

ตอนนี้เราทำแบบเดียวกันกับสัญญาณส่ง เนื่องจากมีเพียงเงื่อนไขเดียวที่สัญญาณการถือเป็นจริงสมการจึงเป็นเพียง:

carry = a & b

ดังนั้นการพกพาจึงง่าย:

                _____
 a ------------|     |
               | AND |---- carry
 b ------------|_____|

เมื่อรวมเข้าด้วยกันเราจะได้สิ่งที่เรียกว่าแอดเดอร์ฮาล์ฟ:

                _____
 a ------;-----|     |
         |     | XOR |---- sum
 b --;---|-----|_____|
     |   |      _____
     |   '-----|     |
     |         | AND |---- carry
     '---------|_____|

สมการของวงจรข้างต้นโดยวิธีนี้:

sum = a ^ b
carry = a & b

บวกครึ่งจะหายไปบางสิ่งบางอย่าง เราได้นำกฎข้อแรกมาใช้ - หากผลลัพธ์มีมากกว่าหนึ่งหลักมากกว่านำไปข้างหน้า แต่เราไม่ได้นำกฎข้อที่สองไปใช้ - หากมีการเพิ่มที่นำไปรวมกับตัวเลข

ดังนั้นในการติดตั้งแอดเดอร์แบบเต็มวงจรเพิ่มที่สามารถเพิ่มตัวเลขที่มีมากกว่าหนึ่งหลักเราต้องกำหนดตารางความจริง:

a b c  |  sum  carry
---------------------
0 0 0  |   0     0
0 0 1  |   1     0
0 1 0  |   1     0
0 1 1  |   0     1
1 0 0  |   1     0
1 0 1  |   0     1
1 1 0  |   0     1
1 1 1  |   1     1

สมการสำหรับผลรวมอยู่ในขณะนี้:

sum = (!a & !b & c) | (!a & b & !c) | (a & !b & !c) | (a & b & c)

เราสามารถผ่านกระบวนการเดียวกันเพื่อแยกแยะและทำให้สมการง่ายขึ้นและตีความมันเป็นวงจร ฯลฯ ตามที่เราทำไปแล้ว แต่ฉันคิดว่าคำตอบนี้ยาวเกินไป

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

  1. สลายปัญหาจนกว่าคุณจะสามารถทำงานในระดับบิตเดียว (หลัก)

  2. กำหนดผลลัพธ์ที่คุณต้องการโดยใช้ตารางความจริง

  3. แปลงตารางเป็นสมการบูลีนและทำให้สมการง่ายขึ้น

  4. ตีความสมการเป็นประตูตรรกะ

  5. แปลงวงจรลอจิกของคุณเป็นวงจรฮาร์ดแวร์จริงโดยใช้ลอจิกเกต

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

ขออภัยฉันไม่มีเวลาอธิบายวิธีใช้การคูณ คุณสามารถลองดูที่รอยแตกโดยการหากฎว่าการคูณนานแค่ไหนแล้วตีความมันเป็นเลขฐานสองแล้วลองแยกมันออกเป็นตารางความจริง หรือคุณสามารถอ่าน Wikipedia: http://en.wikipedia.org/wiki/Binary_multiplier


2

คำแนะนำทางคณิตศาสตร์ขั้นพื้นฐานจะดำเนินการกับคำแนะนำการชุมนุมที่มีประสิทธิภาพสูง

คำแนะนำที่ซับซ้อนมากขึ้น (หรือนามธรรม) สามารถทำได้ในแอสเซมบลีด้วยกลไกการวนซ้ำหรือถูกจัดการใน std libs

เมื่อคุณเรียนคณิตศาสตร์ในวิทยาลัยคุณจะเริ่มเรียนสิ่งต่าง ๆ เช่นแลมบ์ดาแคลคูลัสและสัญลักษณ์ Big-O สิ่งเหล่านี้และอีกมากมายถูกใช้โดยโปรแกรมเมอร์เพื่อประเมินและสร้างอัลกอริธึมที่มีประสิทธิภาพ อย่างไรก็ตามสิ่งพื้นฐานมักจะประสบความสำเร็จในระดับต่ำเช่นในการชุมนุมหรือในคกับพอยน์เตอร์

การแนะนำที่ดีในหัวข้อนี้คือ "รหัส" โดย Charles Petzold


1
หรือตารางการค้นหา เร็วกว่ามากในการคำนวณค่าล่วงหน้าและค้นหามัน ตัวอย่าง Sin / Cos / Tan (การหารจำนวนเต็มแม้ว่าจะคำนวณล่วงหน้าและเก็บไว้ในฮาร์ดแวร์)
Martin York

1

รับหนังสืออย่างพื้นฐานของ Digital Logic ...ซึ่งฉันคิดว่ายังคงเป็นมาตรฐานที่ดีสำหรับนักเรียน Freshman / Sophomore EE และทำงานในแบบของคุณ (ed: มีค่าใช้จ่ายน้อยมากดังนั้นให้มองหารุ่นที่ใช้แล้วหรือรุ่นก่อนหน้าของ มัน). ซึ่งจะนำคุณผ่านผู้เพิ่มและตัวคูณและให้พื้นฐานพอที่จะเริ่มทำความเข้าใจหลักการบางอย่างที่อยู่เบื้องหลังสิ่งที่ฮาร์ดแวร์กำลังทำอยู่

ในระยะสั้นคำตอบของคุณจะกลายเป็น "เพราะมันเข้ากันได้อย่างลงตัวกับตรรกะที่ง่ายกว่าในการทำให้เกิดพฤติกรรมที่ซับซ้อนนี้" แทนที่จะเป็น "เพราะมันเป็นเช่นนั้น"

หากคุณต้องการลองทำความเข้าใจกับหลักการทั้งหมดของการคอมไพล์และรันโปรแกรมให้ใช้วิธีดังกล่าวควบคู่กันไปดังนั้นคุณจะเห็นได้ว่าทุกอย่างตรงกลาง


1

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

a = 5 + 5 + 5 + 5 + 5;           // 5*5, but takes 5 operations
b = (5 << 2) + 5;                // 5*5 in only 2 operations
c = (41 << 4) + (41 << 2) + 41   // 41*21 in 4 operations

แผนกก็สามารถแบ่งย่อยเป็นปฏิบัติการขนาดเล็กได้เช่นกัน XOR (^) เป็นคำสั่งในตัวสำหรับโปรเซสเซอร์ทุกตัวที่ฉันเคยดู แต่ก็สามารถใช้ร่วมกับ AND, OR และ NOT ได้

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


1

นี่คือวิธีที่ตัวประมวลผลที่ทันสมัยอาจใช้การคูณจำนวนเต็ม 64 บิตสองตัว:

คุณรู้วิธีคูณด้วยมือยาว ๆ ในการคูณสองตัวเลข 10 หลักคุณจะคูณหนึ่ง 10 หลักด้วยตัวเลข 10 หลักของตัวเลขอื่น ๆ แล้วเขียน 11 หลักผลลัพธ์หนึ่งที่อยู่ด้านล่างอื่น ๆ แล้วเลื่อนแล้วเพิ่มจำนวนทั้งหมด

ตัวประมวลผลที่ทันสมัยทำสิ่งนี้ด้วย 64 64 บิตทั้งหมด อย่างไรก็ตามการคูณตัวเลขสองบิตนั้นง่ายมาก: 1 x 1 = 1 ผลิตภัณฑ์อื่น ๆ ทั้งหมดเป็นศูนย์ นี่คือการดำเนินการกับตรรกะและ ซึ่งแตกต่างจากผลิตภัณฑ์ทศนิยมที่ผลลัพธ์สามารถเป็นตัวเลขสองหลักได้ผลิตภัณฑ์เลขฐานสองของเลขบิตเดียวจะเป็นหนึ่งบิตเสมอ

ดังนั้นตอนนี้คุณมี 64 แถว 64 บิตที่ต้องเพิ่ม แต่การเพิ่มเติม 64 หมายเลข 64 บิตนั้นเป็นสิ่งที่เตือนไม่ได้ ดังนั้นโปรเซสเซอร์ใช้ adder 3/2 หรือ adder 7/3: หากคุณเพิ่มตัวเลขบิตเดียว 3 ผลลัพธ์อาจเป็น 0, 1, 2 หรือ 3 ซึ่งพอดีกับสองบิต หากคุณเพิ่มตัวเลข 7 บิตเดียวผลลัพธ์จะเป็นตัวเลขตั้งแต่ 0 ถึง 7 ซึ่งสามารถแสดงเป็น 3 บิต IBM อ้างว่าพวกเขาสามารถสร้าง adder 7/3 ด้วยวงจรดั้งเดิมเพียง 18 วงจร (เอกสารประกอบ PowerPC) ฉันเชื่อว่า Intel และ ARM สามารถทำสิ่งนี้ได้เช่นกัน

คุณมี 4096 บิตจัดกลุ่มให้เป็นกลุ่มประมาณ 600 กลุ่มจาก 7 บิตในตำแหน่งบิตเดียวกันและใช้ผู้ประมาณ 600 7/3 เพื่อลดผลลัพธ์จาก 4096 บิตเป็นน้อยกว่า 2,000 จากนั้นคุณก็ทำแบบนี้ซ้ำแล้วซ้ำเล่าจนกว่าคุณจะจบลงด้วยการจับคู่บิตที่สามารถป้อนเข้าไปในแอดเดอร์แบบเต็มธรรมดา

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