เหตุใดจึงมีการใช้ตัวเลขที่ไม่ได้ลงชื่อ?


12

ฉันไม่สามารถเข้าใจได้ว่าทำไมระบบไมโครโปรเซสเซอร์จึงใช้ตัวเลขที่ไม่ได้ลงชื่อ ฉันเดาว่าค่าใช้จ่ายเป็นสองเท่าของจำนวนสาขาที่มีเงื่อนไขเนื่องจากยิ่งน้อยกว่า. etc ต้องการอัลกอริธึมที่แตกต่างจากการเซ็นชื่อยังมีอัลกอริทึมใด ๆ

คำถามของฉันส่วนหนึ่งเป็นเพราะเหตุใดพวกเขาจึงต้องอยู่ในชุดคำสั่งที่ต่างจากคอมไพเลอร์


27
โดยทั่วไปหมายเลขที่ไม่ได้ลงนามเป็นมาตรฐานการลงนามจะดำเนินการเพื่อให้จำนวนลบ
Pieter B

37
ข้อมูลจำนวนมากของโลกนั้นไม่ใช่ตัวเลข ข้อมูลที่ไม่ใช่ตัวเลขสามารถจัดการได้อย่างง่ายดายโดยใช้ประเภทที่ไม่ได้ลงนาม Java นั้นไม่มีประเภทตัวเลขที่ไม่ได้ลงนามนั้นเป็นความล้มเหลวซึ่งทำให้เกิดข้อบกพร่องมากมายในสิ่งต่าง ๆ ที่ต้องจัดการกับข้อมูลที่ไม่ใช่ตัวเลข (เช่นการบีบอัดเป็นต้น)
Erik Eidt

6
@jtw Erik กล่าวว่าไม่มีสิ่งเช่นสีพิกเซลลบหรืออักขระลบ ดังนั้นจึงเป็นการสิ้นเปลืองที่จะใช้จำนวนเต็มที่ลงนามแล้วคุณจะยอมแพ้ครึ่งหนึ่งของพื้นที่ที่อยู่
Martin Maat

26
ฉันไม่แน่ใจว่าฉันอยู่คนเดียวที่นี่ แต่ฉันพบว่ามันหายากอย่างน่าประหลาดใจที่ฉันต้องการเลขจำนวนเต็มเมื่อทำการพัฒนาแอปพลิเคชัน เกือบตลอดเวลาสิ่งที่ฉันต้องการคือหมายเลขธรรมชาติ (ไม่ได้ลงนาม) (ขนาดบวกปกติ) หรือเลขทศนิยมที่ลงชื่อ ข้อยกเว้นคือสิ่งต่าง ๆ เช่นสกุลเงิน แต่ก็มีน้อยมาก สำหรับฉันแล้วเลขจำนวนเต็มที่ไม่ได้ลงนามเป็นบรรทัดฐานและจำนวนเต็มที่ลงนามนั้นเป็นข้อยกเว้น!
โทมัส

11
จากมุมมองของ CPU ตัวเลขทั้งหมดค่อนข้างไม่ได้ลงนาม คำแนะนำเล็กน้อยสามารถแปลบิตเป็นลายเซ็น (.eg arithmetic-right-shift) แต่ส่วนประกอบที่แท้จริงของทั้งสองทำให้ซีพียูรักษาจำนวนเต็มที่ลงนามเป็นจำนวนเต็มที่ไม่ได้ลงนามซึ่งหมายความว่าไม่ต้องการวงจรพิเศษ (หรือน้อยมาก) สำหรับ CPU เพื่อสนับสนุนทั้งคู่ .
Cornstalks

คำตอบ:


39

ตัวเลขที่ไม่ได้ลงนามเป็นหนึ่งการตีความของลำดับของบิต มันเป็นวิธีที่ง่ายที่สุดและการตีความที่ใช้มากที่สุดภายใน CPU เนื่องจากที่อยู่และรหัส op เป็นบิตเพียงอย่างเดียว ที่อยู่หน่วยความจำ / สแต็คและเลขคณิตเป็นพื้นฐานของไมโครโปรเซสเซอร์, ดี, การประมวลผล การเลื่อนขึ้นไปบนปิรามิดที่เป็นนามธรรมการตีความอีกครั้งของบิตคือตัวละคร (ASCII, Unicode, EBCDIC) จากนั้นก็มีการตีความอื่น ๆ เช่น IEEE Floating point, RGBA สำหรับกราฟิกและอื่น ๆ สิ่งเหล่านี้ไม่ใช่ตัวเลขที่มีการลงนามแบบง่าย ๆ (IEEE FP นั้นไม่ง่ายและการคำนวณทางคณิตศาสตร์โดยใช้นั้นซับซ้อนมาก)

นอกจากนี้ด้วยเลขคณิตที่ไม่ได้ลงนามมันค่อนข้างตรงไปตรงมา (ถ้าไม่ได้มีประสิทธิภาพมากที่สุด) เพื่อดำเนินการอื่น ๆ การสนทนาไม่เป็นความจริง


3
EBCDIC มีเพียง "I" เพียงหนึ่งเดียว
Ruslan

4
@Ruslan - แต่มันออกเสียงเหมือนว่ามันมีสอง <g>
Pete Becker

5
@PeteBecker ไม่มันไม่ใช่ EBCDIC ออกเสียงว่าeb -see-dick
Mike Nakis

19

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

  • ไม่ว่าบิตทั้งหมดจะเป็นศูนย์ (เช่นเงื่อนไขเท่ากัน)
  • บิตเครื่องหมายของผลลัพธ์
  • บิตนำของการลบ (เช่นบิตลำดับสูง 33 บนคอมพิวเตอร์ 32 บิต)

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

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


1
การเปรียบเทียบตัวเลขที่ไม่ได้ลงชื่อไม่จำเป็นต้องมีการลบ มันอาจทำได้โดยการเปรียบเทียบจากซ้ายไปขวา
Jonathan Rosenne

10
@JonathanRosenne แต่นั่นไม่ใช่วิธีที่โปรเซสเซอร์ใช้งานได้ ในทางตรงกันข้ามมันแทบจะไม่สามารถคิดได้สำหรับโปรเซสเซอร์ 2's ที่จะไม่ใช้การลบ (มีหรือไม่มีการพกพา / ยืม) ใน ALU หลังจากนั้นความคิดของนักออกแบบก็คือใช้ ALU ที่จำเป็นนี้เพื่อฆ่านกตัวอื่นด้วยหินก้อนเดียวกัน การเปรียบเทียบจะกลายเป็นการลบโดยที่ผลลัพธ์ไม่ถูกเขียนกลับไปยังไฟล์ลงทะเบียน
Iwillnotexist Idonotexist

4
+1: นี่คือคำตอบที่ถูกต้องสำหรับคำถามที่ถาม สรุป: เพราะการดำเนินการการดำเนินงานไม่ได้ลงนามเป็นเกือบฟรีเมื่อคุณได้ดำเนินการแล้วลงนาม
Periata Breatta

10
@PeriataBreatta นอกจากนี้ยังทำงานในลักษณะอื่น ๆ ตัวเลขที่เซ็นชื่อและไม่ได้ลงชื่อในซีพียูสมัยใหม่เกือบเหมือนกันซึ่งเป็นประเด็นหลักที่ OP ไม่รู้จัก แม้แต่คำแนะนำในการเปรียบเทียบยังเหมือนกันสำหรับการเซ็นชื่อและไม่ได้ลงชื่อ - นั่นเป็นหนึ่งในเหตุผลว่าทำไมการเติมเต็มของสองคนจึงชนะสงครามจำนวนเต็มแบบ :)
Luaan

3
@svidgen> เป็นคำตอบอื่น ๆ ที่บอกว่ามันทำงานในทางอื่น ๆ ข้อกังวลหลักคือตัวเลขที่ไม่ได้ลงชื่อซึ่งใช้สำหรับทุกสิ่งโดยทั่วไป (ที่อยู่หน่วยความจำ, io / พอร์ต, การแสดงตัวอักษร, ... ) หมายเลขที่ลงนามนั้นมีราคาถูกเมื่อคุณไม่ได้ลงชื่อและมีประโยชน์ในกรณีที่หายากซึ่งเป็นที่ต้องการ
spectras

14

เพราะถ้าคุณจำเป็นต้องนับบางสิ่งที่อยู่เสมอ >= 0คุณจะต้องลดพื้นที่ในการนับเป็นครึ่งโดยใช้จำนวนเต็มที่ลงนามแล้วโดยไม่จำเป็น

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

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

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

อืม ... ประสิทธิภาพ!

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


2
ในบรรทัดเหล่านี้คุณสามารถบันทึกการทำงานด้วยตัวเองเมื่อทำการตรวจสอบขอบเขตของอาร์เรย์ หากคุณใช้จำนวนเต็มที่ไม่ได้ลงนามคุณจะต้องตรวจสอบว่าดัชนีที่ระบุมีขนาดน้อยกว่าขนาดอาร์เรย์ (เพราะไม่สามารถลบได้)
riwalk

2
@ dan04 เป็นไปได้อย่างแน่นอน ... แต่ถ้าคุณใช้ int เพิ่มค่าอัตโนมัติเริ่มต้นที่ 0 หรือ 1 ซึ่งเป็นเรื่องธรรมดาทั่วไปคุณได้ห้ามการใช้ตัวเลขครึ่งหนึ่งของจำนวนที่มีอยู่ และในขณะที่คุณสามารถเริ่มนับได้ที่ -2 ^ 31 (หรืออะไรก็ตาม) คุณจะมีตัวอักษร "edge" ที่มีศักยภาพอยู่ตรงกลางของ id space ของคุณ
svidgen

1
การตัดสาขาของคุณครึ่งหนึ่งเป็นเรื่องที่ค่อนข้างอ่อนแอ โอกาสที่แอปของคุณต้องการมากกว่า 2 พันล้านแอปมันก็ต้องการมากกว่า 4 พันล้านครั้ง
corsiKa

1
@corsiKa: ด้วยเหตุผลนั้นถ้ามันต้องการมากกว่า 4 มันอาจต้องมี 8, 16 และ 16 ฯลฯ มันจะจบที่ไหน?
whatsisname

1
โดยทั่วไป @whatsisname คุณใช้ชนิดจำนวนเต็ม 8, 16, 32 หรือ 64 บิต การบอกว่าการไม่ได้ลงนามนั้นดีกว่าเพราะคุณได้รับ 32 บิตทั้งหมดแทนที่จะเป็นจำนวน จำกัดช่วง 31 บิตของจำนวนเต็มบวกในช่องว่างที่มีการเซ็นชื่อในไบต์
corsiKa

9

คำถามของคุณประกอบด้วยสองส่วน:

  1. จุดประสงค์ของจำนวนเต็มที่ไม่ได้ลงนามคืออะไร?

  2. จำนวนเต็มที่ไม่มีลายเซ็นนั้นคุ้มค่ากับปัญหาหรือไม่

1. จุดประสงค์ของจำนวนเต็มที่ไม่ได้ลงนามคืออะไร?

ตัวเลขที่ไม่ได้ลงนามค่อนข้างง่ายหมายถึงคลาสของปริมาณที่ค่าลบไม่มีความหมาย แน่นอนคุณอาจพูดว่าคำตอบสำหรับคำถาม "ฉันมีแอปเปิ้ลกี่ตัว?" อาจเป็นตัวเลขติดลบหากคุณเป็นหนี้แอปเปิ้ลกับใครบางคน แต่คำถามของ "ฉันมีหน่วยความจำเท่าไหร่?" - คุณไม่สามารถมีหน่วยความจำติดลบได้ ดังนั้นจำนวนเต็มที่ไม่ได้ลงนามนั้นเหมาะสมมากสำหรับการแสดงปริมาณดังกล่าวและพวกเขามีประโยชน์ที่จะสามารถแสดงช่วงของค่าบวกสองเท่ากว่าจำนวนเต็มที่ลงนามได้ ตัวอย่างเช่นค่าสูงสุดที่คุณสามารถแสดงด้วยจำนวนเต็ม 16 บิตที่ลงนามคือ 32767 ในขณะที่มีจำนวนเต็มไม่ได้ลงนาม 16 บิตมันคือ 65535

2. จำนวนเต็มที่ไม่มีลายเซ็นคุ้มค่าหรือไม่?

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

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

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

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


1
คำถามของฉันสันนิษฐานว่าทั้งหมดนี้โดยอัลกอริทึมฉันหมายถึงกฎที่น้อยกว่ามากกว่า ฯลฯ นั้นแตกต่างกัน ค่าใช้จ่ายที่ฉันเห็นนั้นมีคำแนะนำเพิ่มเติมมากมาย หากโปรแกรมระดับสูงต้องการดูข้อมูลเป็นรูปแบบของบิตสิ่งนี้สามารถนำไปใช้งานได้อย่างง่ายดายโดยคอมไพเลอร์
jtw

3
@jtw - แต่ประเด็นก็คือคำแนะนำพิเศษเหล่านั้นคล้ายกับคำแนะนำที่จำเป็นสำหรับหมายเลขที่ลงชื่อและวงจรเกือบทั้งหมดที่จำเป็นสำหรับพวกเขาสามารถแชร์ได้ ค่าใช้จ่ายเพิ่มเติมของการใช้งานทั้งสองประเภทเกือบเป็นศูนย์
Periata Breatta

1
ใช่ที่ตอบคำถามของฉันการเพิ่มคำสั่งสาขาเพิ่มเติมมาพร้อมกับค่าใช้จ่ายเล็กน้อยและพวกเขามักจะมีประโยชน์ในการปฏิบัติ
jtw

1
"การดำเนินการที่ไม่ได้ลงชื่อต้องมีการจัดการเป็นพิเศษเมื่อพูดถึงการหารและการคูณ"ฉันคิดว่าคุณมีสิ่งที่ล้าหลัง การคูณและการหารทำได้ง่ายขึ้นด้วยค่าที่ไม่ได้ลงนาม จำเป็นต้องมีการจัดการพิเศษเพื่อจัดการกับตัวถูกดำเนินการที่ลงนามแล้ว
Cody Gray

@CodyGray ฉันรู้ว่ามีคนจะปรากฏขึ้นเพื่อพูดแบบนี้ คุณพูดถูก นี่คือเหตุผลที่อยู่เบื้องหลังคำแถลงของฉันซึ่งฉันละทิ้งเพื่อความกะทัดรัด: CPU ไม่สามารถเสนอการคูณและการหารที่ไม่ได้ลงชื่อเท่านั้นเนื่องจากเวอร์ชันที่เซ็นชื่อนั้นมีประโยชน์มาก แท้ที่จริงการคูณและการหารที่ได้รับการลงนามเป็นสิ่งจำเป็น ไม่ได้ลงนามเป็นตัวเลือก ดังนั้นถ้าไม่ได้ลงนามเป็นที่จะยังนำเสนอนี้สามารถมองเห็นเป็นต้องมีวงจรบิตขนาดเล็กมากขึ้น
Mike Nakis

7

ไมโครโปรเซสเซอร์นั้นไม่ได้ลงนามโดยเนื้อแท้ หมายเลขที่เซ็นชื่อเป็นสิ่งที่นำไปใช้งานไม่ใช่วิธีอื่น ๆ

คอมพิวเตอร์สามารถทำงานได้ดีโดยไม่ต้องมีหมายเลขที่ลงนาม แต่สำหรับเรามันเป็นมนุษย์ที่ต้องการตัวเลขที่เป็นลบ


4
ไมโครโปรเซสเซอร์จำนวนมากมีทั้งคำสั่งที่ลงชื่อและไม่ได้ลงชื่อสำหรับการดำเนินการต่างๆ
whatsisname

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

3

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

ตอนนี้ถ้าคุณต้องการตัวอย่างที่คุณจะต้องบิตพิเศษนี้มีมากมายที่จะพบถ้าคุณดู

ตัวอย่างที่ฉันชอบมาจาก bitboards ในเครื่องมือหมากรุก บนกระดานหมากรุกมีทั้งหมด 64 ช่องจึงเป็นunsigned longพื้นที่จัดเก็บข้อมูลที่สมบูรณ์แบบสำหรับอัลกอริทึมที่หลากหลายซึ่งหมุนรอบการสร้างแบบเคลื่อนไหว เมื่อพิจารณาถึงข้อเท็จจริงที่ว่าคุณจำเป็นต้องดำเนินการแบบไบนารี (เช่นเดียวกับการทำงานแบบเลื่อน !!) มันง่ายที่จะเห็นว่าทำไมมันง่ายกว่าที่จะไม่ต้องกังวลเกี่ยวกับสิ่งพิเศษที่เกิดขึ้นหากมีการตั้ง MSB มันสามารถทำได้ด้วยการลงนามยาว แต่มันเป็นเรื่องง่ายมากที่จะใช้ไม่ได้ลงนาม


3

การมีภูมิหลังทางคณิตศาสตร์ที่บริสุทธิ์นี่เป็นวิธีการทางคณิตศาสตร์ที่มากกว่าสำหรับผู้ที่สนใจ

ถ้าเราเริ่มด้วยจำนวนเต็ม 8 บิตที่ลงนามและไม่ได้ลงนามสิ่งที่เรามีก็คือจำนวนเต็ม modulo 256 เท่าที่มีการเพิ่มและการคูณให้คำนึงถึงการเติมเต็มของ 2 จะใช้แทนจำนวนเต็มลบ .

สิ่งที่แตกต่างกันอยู่ในสองแห่ง: หนึ่งคือการดำเนินการเปรียบเทียบ เรียกอีกอย่างหนึ่งว่าจำนวนเต็มโมดูโล 256 นั้นถือว่าเป็นวงกลมของตัวเลขที่ดีที่สุด (เช่นจำนวนเต็มโมดูโล 12 ทำบนหน้าปัดแบบอะนาล็อกแบบเก่า) ในการทำการเปรียบเทียบเชิงตัวเลข (คือ x <y) มีความหมายเราจำเป็นต้องตัดสินใจว่าตัวเลขใดมีค่าน้อยกว่าตัวเลขอื่น จากมุมมองของนักคณิตศาสตร์เราต้องการฝังจำนวนเต็มโมดูโล 256 ลงในชุดของจำนวนเต็มทั้งหมดอย่างใด การทำแผนที่จำนวนเต็ม 8 บิตซึ่งการเป็นตัวแทนไบนารีคือศูนย์ทั้งหมดถึงจำนวนเต็ม 0 เป็นสิ่งที่ชัดเจนที่จะทำ จากนั้นเราสามารถดำเนินการแมปอื่น ๆ เพื่อให้ '0 + 1' (ผลลัพธ์ของการ zeroing register บอกว่า ax และการเพิ่มขึ้นทีละหนึ่งโดยใช้ 'inc ax') จะไปที่จำนวนเต็ม 1 เป็นต้น เราสามารถทำเช่นเดียวกันกับ -1 เช่นการแมป '0-1' กับจำนวนเต็ม -1 และ '0-1-1' เป็นจำนวนเต็ม -2 เราต้องมั่นใจว่าการฝังนี้เป็นฟังก์ชั่นดังนั้นจึงไม่สามารถแมปจำนวนเต็ม 8 บิตเดียวกับจำนวนเต็มสองตัว เช่นนี้หมายความว่าถ้าเราแมปตัวเลขทั้งหมดเข้าไปในชุดจำนวนเต็ม 0 จะอยู่ที่นั่นพร้อมกับจำนวนเต็มน้อยกว่า 0 และบางส่วนมากกว่า 0 มี 255 วิธีหลักในการทำสิ่งนี้ด้วยจำนวนเต็ม 8 บิต (ตาม เป็นค่าต่ำสุดที่คุณต้องการตั้งแต่ 0 ถึง -255) จากนั้นคุณสามารถกำหนด 'x <y' ในรูปของ '0 <y - x'

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

อีกประเด็นคือการแม็พจำนวนเต็ม 8 บิตลงในช่องว่างของจำนวนเต็ม 16 บิต -1 ไปที่ -1 หรือไม่ นี่คือสิ่งที่คุณต้องการหาก 0xFF หมายถึงการแสดง -1 ในกรณีนี้การขยายสัญญาณคือสิ่งที่สมเหตุสมผลที่ต้องทำดังนั้น 0xFF จะไปที่ 0xFFFF ในทางตรงกันข้ามถ้า 0xFF หมายถึงการแสดง 255 แล้วคุณต้องการให้แมปเป็น 255 ดังนั้น 0x00FF แทนที่จะเป็น 0xFFFF

นี่คือความแตกต่างระหว่างการดำเนินการ 'shift' และ 'arithmetic shift' เช่นกัน

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


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

2

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

CPU ทั่วไปต้องการคำแนะนำทางคณิตศาสตร์ต่อไปนี้:

  • เพิ่ม (ซึ่งเพิ่มสองค่าและตั้งค่าสถานะหากการดำเนินการมากเกินไป)
  • SUB (ซึ่งจะลบค่าหนึ่งจากอีกค่าหนึ่งและตั้งค่าสถานะต่าง ๆ - เราจะอธิบายด้านล่างนี้)
  • CMP (ซึ่งเป็นหลัก 'SUB และทิ้งผลลัพธ์ให้เก็บค่าสถานะเท่านั้น')
  • LSH (กะซ้ายตั้งค่าสถานะเป็นโอเวอร์โฟลว์)
  • RSH (กะขวาตั้งค่าสถานะถ้า 1 ถูกเลื่อนออกไป)
  • ความหลากหลายของคำแนะนำข้างต้นทั้งหมดที่จัดการกับการถือครอง / ยืมจากธงดังนั้นให้คุณเชื่อมโยงคำแนะนำเข้าด้วยกันเพื่อให้ทำงานได้อย่างสะดวกในประเภทที่ใหญ่กว่าการลงทะเบียน CPU
  • MUL (เพิ่มทวีคูณตั้งค่าสถานะ ฯลฯ - ไม่มีให้บริการในระดับสากล)
  • DIV (แบ่งตั้งค่าสถานะ ฯลฯ - สถาปัตยกรรม CPU จำนวนมากขาดสิ่งนี้)
  • ย้ายจากประเภทจำนวนเต็มขนาดเล็ก (เช่น 16 บิต) ไปเป็นประเภทที่ใหญ่กว่า (เช่น 32 บิต) สำหรับเลขจำนวนเต็มที่ลงนามนี้มักจะเรียกว่า MOVSX (ย้ายด้วยการขยายสัญญาณ)

นอกจากนี้ยังต้องการคำแนะนำเชิงตรรกะ:

  • สาขาในศูนย์
  • สาขาใหญ่ขึ้น
  • สาขาน้อย
  • สาขาที่ล้น
  • รุ่นเมื่อตะกี้จากทั้งหมดข้างต้น

เพื่อดำเนินการสาขาดังกล่าวข้างต้นในการเปรียบเทียบจำนวนเต็มลงนามวิธีที่ง่ายที่สุดคือการมีคำสั่ง SUB ตั้งค่าสถานะต่อไปนี้:

  • ศูนย์. ตั้งค่าถ้าการลบส่งผลให้มีค่าเป็นศูนย์
  • ล้น. ตั้งค่าถ้าการลบยืมค่าจากบิตที่สำคัญที่สุด
  • สัญญาณ ตั้งค่าเป็นเครื่องหมายบิตของผลลัพธ์

จากนั้นสาขาคณิตศาสตร์จะถูกดำเนินการดังต่อไปนี้:

  • สาขาเป็นศูนย์: ถ้าตั้งค่าสถานะเป็นศูนย์
  • สาขาน้อย: หากธงสัญญาณแตกต่างจากธงล้น
  • สาขามากกว่า: ถ้าธงเครื่องหมายเท่ากับธงล้นและธงศูนย์ชัดเจน

การปฏิเสธเหล่านี้ควรติดตามอย่างชัดเจนจากวิธีการนำไปปฏิบัติ

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

  • เพิ่ม - การดำเนินการของเพิ่มเหมือนกัน
  • SUB - เราจำเป็นต้องเพิ่มการตั้งค่าสถานะพิเศษ: การดำเนินการตั้งค่าสถานะเมื่อมีการยืมค่าจากเกินบิตที่สำคัญที่สุดของการลงทะเบียน
  • CMP - ไม่เปลี่ยนแปลง
  • LSH - ไม่เปลี่ยนแปลง
  • RSH - การเลื่อนที่ถูกต้องสำหรับค่าที่เซ็นชื่อจะเก็บค่าของบิตที่สำคัญที่สุด สำหรับค่าที่ไม่ได้ลงนามเราควรตั้งค่าเป็นศูนย์แทน
  • มัล - ถ้าขนาดของคุณออกเป็นเช่นเดียวกับการป้อนข้อมูลที่ไม่มีการจัดการพิเศษจะต้อง (x86 ไม่ได้มีการจัดการพิเศษ แต่เพราะมันมีการส่งออกเป็นคู่ลงทะเบียน แต่ทราบว่าสถานที่นี้เป็นจริงค่อนข้างไม่ค่อยได้ใช้จึงจะเป็น ผู้สมัครที่ชัดเจนกว่าที่จะออกจากโปรเซสเซอร์มากกว่าประเภทที่ไม่ได้ลงนาม)
  • DIV - ไม่จำเป็นต้องมีการเปลี่ยนแปลง
  • ย้ายจากประเภทที่มีขนาดเล็กลงไปเป็นประเภทที่มีขนาดใหญ่ขึ้น - จำเป็นต้องเพิ่ม MOVZX ย้ายด้วยการขยายศูนย์ โปรดทราบว่า MOVZX นั้นใช้ง่ายมาก
  • สาขาในศูนย์ - ไม่เปลี่ยนแปลง
  • สาขาย่อย - กระโดดข้ามเมื่อพกชุดธง
  • สาขาใหญ่ - กระโดดถ้าถือธงและศูนย์ทั้งสองชัดเจน

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

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


ขอบคุณคำตอบนี้เป็นคำถามของฉันค่าใช้จ่ายน้อยและคำแนะนำนั้นมีประโยชน์บ่อยครั้ง
jtw

1
การคูณเลขสองครั้งที่ไม่ได้ลงชื่อเป็นสิ่งจำเป็นเมื่อทำการคำนวณทางคณิตศาสตร์ที่มีความแม่นยำสูงและอาจดีสำหรับการปรับปรุงความเร็วโดยรวมที่ดีกว่า 2x โดยรวมเมื่อทำการเข้ารหัส RSA นอกจากนี้ยังมีส่วนที่แตกต่างกันในกรณีการลงนามและไม่ได้ลงนาม แต่เนื่องจากกรณีที่ได้รับการรับรองเป็นเรื่องง่ายและการแบ่งเป็นพอที่หายากและช้าพอว่าการเพิ่มคำแนะนำไม่กี่จะไม่เจ็บมากสิ่งที่ง่ายที่สุดในการทำจะใช้เฉพาะส่วนที่ไม่ได้ลงชื่อ แล้วล้อมด้วยตรรกะการจัดการสัญญาณ
supercat

2

ตัวเลขที่ไม่ได้ลงนามนั้นมีอยู่เป็นส่วนใหญ่ในการจัดการกับสถานการณ์ที่เราต้องการแหวนพีชคณิตแบบห่อ (สำหรับประเภทที่ไม่มีเครื่องหมาย 16 บิตมันจะเป็นวงแหวนของจำนวนเต็มสอดคล้องกัน 65536) รับค่าเพิ่มจำนวนใด ๆ ที่น้อยกว่าโมดูลัสและความแตกต่างระหว่างสองค่าจะเป็นจำนวนเงินที่ถูกเพิ่มเข้าไป เป็นตัวอย่างในโลกแห่งความจริงหากเครื่องวัดค่าสาธารณูปโภคอ่าน 9995 เมื่อเริ่มต้นหนึ่งเดือนและอีกหนึ่งใช้ 23 หน่วยเครื่องวัดจะอ่าน 0018 ในตอนท้ายของเดือน เมื่อใช้ประเภทพีชคณิตริงไม่จำเป็นต้องทำอะไรเป็นพิเศษในการจัดการกับปัญหาน้ำล้น การลบ 9995 จาก 0018 จะให้ผลเป็น 0023 จำนวนหน่วยที่ใช้

บน PDP-11 เครื่องที่ใช้งาน C เป็นครั้งแรกไม่มีประเภทจำนวนเต็มที่ไม่ได้ลงนาม แต่ประเภทที่ลงนามนั้นสามารถใช้สำหรับเลขคณิตแบบแยกส่วนซึ่งห่อหุ้มระหว่าง 32767 และ -32768 มากกว่าระหว่าง 65535 และ 0 คำแนะนำจำนวนเต็มในที่อื่น ๆ แพลตฟอร์มไม่ห่อสิ่งต่าง ๆ อย่างเรียบร้อยอย่างไรก็ตาม แทนที่จะต้องการให้ implementations ต้องเลียนแบบจำนวนเต็มสองส่วน - ของที่ใช้ใน PDP-11 ภาษาแทนที่จะเพิ่มประเภทที่ไม่ได้ลงนามซึ่งส่วนใหญ่จะต้องทำตัวเหมือนแหวนพีชคณิตและอนุญาตให้ทำตัวเป็นจำนวนเต็มประเภทอื่น ๆ ในกรณีที่ล้น

ในวันแรกของ C มีจำนวนมากซึ่งอาจเกิน 32767 (INT_MAX ทั่วไป) แต่ไม่ใช่ 65535 (UINT_MAX ทั่วไป) ดังนั้นจึงเป็นเรื่องธรรมดาที่จะใช้ประเภทที่ไม่ได้ลงชื่อเพื่อเก็บปริมาณดังกล่าว (เช่น size_t) น่าเสียดายที่ไม่มีสิ่งใดในภาษาที่จะแยกแยะความแตกต่างระหว่างประเภทที่ควรทำตัวเหมือนตัวเลขที่มีช่วงบวกพิเศษเพิ่มขึ้นเล็กน้อยเมื่อเทียบกับประเภทที่ควรทำตัวเหมือนวงแหวนพีชคณิต แต่ภาษาจะทำให้ชนิดเล็กกว่า "int" ที่ทำตัวเหมือนตัวเลขในขณะที่ชนิดเต็มขนาดจะทำตัวเหมือนวงแหวนพีชคณิต ดังนั้นฟังก์ชั่นการโทรเช่น:

uint32_t mul(uint16_t a, uint16_t b) { return a*b; }

ด้วย (65535, 65535) จะมีหนึ่งพฤติกรรมที่กำหนดไว้ในระบบที่intเป็น 16 บิต (เช่นกลับ 1) พฤติกรรมที่แตกต่างกันที่int33 บิตหรือใหญ่กว่า (กลับ 0xFFFE0001) และพฤติกรรมที่ไม่ได้กำหนดบนระบบที่ "int" อยู่ทุกที่ ระหว่าง [โปรดทราบว่า gcc มักจะให้ผลลัพธ์ที่ถูกต้องทางคณิตศาสตร์กับผลลัพธ์ระหว่าง INT_MAX + 1u และ UINT_MAX แต่บางครั้งจะสร้างรหัสสำหรับฟังก์ชั่นด้านบนซึ่งล้มเหลวด้วยค่าดังกล่าว!] ไม่ค่อยมีประโยชน์

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

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