ทำไม Java ไม่สนับสนุน ints ที่ไม่ได้ลงชื่อ?


374

เหตุใด Java จึงไม่รวมการสนับสนุนสำหรับจำนวนเต็มที่ไม่มีเครื่องหมาย?

ดูเหมือนว่าฉันจะไม่สนใจคี่เพราะพวกเขาอนุญาตให้หนึ่งเขียนรหัสที่มีโอกาสน้อยที่จะผลิตล้นในการป้อนข้อมูลขนาดใหญ่โดยไม่คาดคิด

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

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

ข้อเสียของการรวมสิ่งเหล่านี้คืออะไร?


137
ฉันไม่รู้ แต่มันสร้างความรำคาญให้กับฉัน เช่นมันยากที่จะเขียนรหัสเครือข่ายด้วยวิธีนี้
Tamas Czinege

20
ฉันต้องการมีเพียงสองประเภทในภาษาฐานข้อมูล / / ... โลก: จำนวนและสตริง :)
เหลียว

5
การเขียนรหัสเครือข่ายนั้นไม่ยากเลย BTW InputStream.read () ส่งคืนไบต์ที่ไม่ได้ลงนามไม่ใช่ตัวอย่างที่ลงชื่อดังนั้นตัวอย่างเครือข่ายจึงเป็นความสับสน IMHO ความสับสนเพียงอย่างเดียวคือคุณคิดว่าการเขียนค่าที่ลงนามนั้นแตกต่างจากการเขียนค่าที่ไม่ได้ลงชื่อ เช่นถ้าคุณไม่รู้จริง ๆ ว่าเกิดอะไรขึ้นในระดับไบต์
Peter Lawrey

19
@ ZachSaw - ฉันยังทำสองครั้งเมื่อฉันเห็นนักออกแบบภาษาทำใบเสนอราคานั้น ไม่มีอะไรง่ายไปกว่าจำนวนเต็มที่ไม่มีเครื่องหมาย เลขจำนวนเต็มที่ลงนามนั้นซับซ้อน โดยเฉพาะอย่างยิ่งเมื่อคุณพิจารณาบิต twiddling ที่ระดับทรานซิสเตอร์ และจำนวนเต็มลงนามกะอย่างไร ฉันต้องสรุปว่าผู้ออกแบบ Java มีปัญหาร้ายแรงในการทำความเข้าใจตรรกะบูลีน
PP

8
สำหรับฉันมันยากที่จะทำการประมวลผลภาพใด ๆ กับภาพที่byteไม่สามารถให้140ระดับสีเทาแบบตรงแต่เป็นสิ่ง-116ที่คุณต้อง& 0xffได้รับค่าที่ถูกต้อง
Matthieu

คำตอบ:


193

นี่คือจากการสัมภาษณ์กับกอสลิงและอื่น ๆเกี่ยวกับความเรียบง่าย:

ลูกห่าน: สำหรับฉันในฐานะนักออกแบบภาษาซึ่งฉันไม่นับตัวเองว่าเป็นวันนี้สิ่งที่ "เรียบง่าย" จบลงด้วยความหมายที่แท้จริงฉันคาดหวังได้เลยว่า J. Random Developer จะถือสเป็คไว้ในหัวของเขา คำจำกัดความดังกล่าวบอกว่ายกตัวอย่างเช่น Java ไม่ใช่ - และในความเป็นจริงภาษาเหล่านี้ส่วนใหญ่จบลงด้วยการเป็นมุมเล็ก ๆ น้อย ๆ สิ่งที่ไม่มีใครเข้าใจจริงๆ ทำแบบทดสอบนักพัฒนา C ทุกคนเกี่ยวกับผู้ที่ไม่ได้ลงนามและในไม่ช้าคุณก็จะค้นพบว่าแทบจะไม่มีนักพัฒนา C คนใดที่เข้าใจสิ่งที่เกิดขึ้นโดยไม่ได้ลงนามสิ่งที่ไม่ได้ลงนามคืออะไร สิ่งที่ทำนั้นซับซ้อน C ฉันคิดว่าส่วนภาษาของ Java นั้นค่อนข้างเรียบง่าย ห้องสมุดที่คุณต้องค้นหา


222
ฉันจะต้องไม่เห็นด้วยกับลูกห่านที่นี่ด้วยตัวอย่างที่เฉพาะเจาะจง (จาก CLR ไม่น้อยกว่า) มีอะไรที่ทำให้เกิดความสับสนมากขึ้นในการให้ Array มีค่าความยาวจำนวนเต็มที่ลงนามหรือความยาวที่ไม่ได้ลงชื่อ? เป็นไปไม่ได้ที่อาร์เรย์จะมีความยาวเชิงลบ แต่ API ของเราระบุว่าเป็นไปได้
JaredPar

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

59
หาก Java ต้องการเลขจำนวนเต็มที่ไม่ได้ลงนามเนื่องจากดัชนี Array ไม่สามารถเป็นลบได้ดังนั้นจึงจำเป็นต้องใช้รูทีนย่อย (a la Pascal) เนื่องจากดัชนีอาร์เรย์ต้องไม่มากกว่าขนาดอาร์เรย์
Wayne Conrad

81
โอเคเขาเพิ่งบอกข้อดีของการไม่มีประเภทไม่ได้ลงนาม ตอนนี้ลองนับข้อเสีย ...
Moshe Revah

83
ฉันชอบความเรียบง่ายของรหัสมากกว่าความเรียบง่ายของภาษา นั่นเป็นเหตุผลที่ฉันเกลียดชวา
Pijusn

50

อ่านระหว่างบรรทัดฉันคิดว่าตรรกะเป็นอะไรเช่นนี้:

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

ส่วนใหญ่ฉันจะบอกว่ามันเป็นการตัดสินใจที่สมเหตุสมผล อาจเป็นไปได้ที่ฉันจะมี:

  • ทำ byte unsigned หรืออย่างน้อยก็ให้ทางเลือกที่ลงชื่อ / ไม่ได้ลงนามอาจมีชื่อแตกต่างกันสำหรับชนิดข้อมูลนี้ (ทำให้การลงชื่อนั้นดีสำหรับความสอดคล้อง แต่เมื่อใดที่คุณต้องการไบต์ที่ลงนามแล้ว)
  • เสร็จแล้วด้วย 'สั้น' (เมื่อคุณใช้เลขคณิตแบบ 16 บิตครั้งล่าสุดเมื่อใด)

การดำเนินการกับค่าที่ไม่ได้ลงนามมากถึง 32 บิตนั้นยังไม่ดีนักและคนส่วนใหญ่ไม่ต้องการการแบ่งหรือเปรียบเทียบแบบ 64 บิตที่ไม่ได้ลงชื่อ


2
ฉันชอบที่จะมีไบต์ที่ไม่ได้ลงนามเช่นกัน แต่ฉันสงสัยว่าประโยชน์ของความสอดคล้องที่สมบูรณ์ในประเภทจำนวนเต็มนั้นมากกว่าความสะดวกสบายที่ไบต์ที่ไม่ได้ลงนามจะนำมาใช้
อลันมัวร์

64
"เพื่อจุดประสงค์ในชีวิตประจำวันพวกเขารู้สึกว่าความต้องการที่พบมากที่สุดคือประเภทข้อมูลที่ถูกเซ็นชื่อ" ในรหัส C ++ ของฉันฉันมักจะพบว่าตัวเองคิดว่า "ทำไมในโลกนี้ฉันจึงใช้จำนวนเต็มที่ลงนามที่นี่แทนที่จะเป็นคนที่ไม่ได้ลงชื่อ?!" ฉันมีความรู้สึกว่า "การเซ็นชื่อ" เป็นข้อยกเว้นมากกว่ากฎ (แน่นอนมันขึ้นอยู่กับโดเมน แต่มีเหตุผลว่าทำไมจำนวนเต็มบวกเรียกว่าจำนวนธรรมชาติ ;-))
Luc Touraille

15
ยกนิ้วให้สำหรับการเรียกใช้ไบต์ที่ไม่ได้ลงชื่อเมื่อทำการประมวลผลภาพโดยสมมติว่าไบต์นั้นไม่ได้ลงนาม (ตามที่ควรจะเป็น) ทำให้ฉันใช้เวลาในการดีบักเป็นชั่วโมง
Helin Wang

7
คุณจะประหลาดใจที่ความถี่shortถูกใช้ - อัลกอริธึม defltate / gzip / inflate เป็น 16 บิตและพวกเขาพึ่งพากางเกงขาสั้นอย่างหนัก ... หรืออย่างน้อยshort[][ยอมรับอย่างเป็นพื้นเมือง - แต่จาวา impl ของอัลกอริทึมที่มีพื้นที่ของข้อมูล] หลัง ( short[]) มีข้อได้เปรียบที่สำคัญint[]เนื่องจากใช้หน่วยความจำน้อยกว่าสองเท่าและหน่วยความจำน้อยกว่า = คุณสมบัติการแคชที่ดีขึ้นประสิทธิภาพที่ดีขึ้นมาก
bestsss

8
แม้ว่าในแอพพลิเคชั่นเฉพาะคุณควรวัดว่าการใช้กางเกงขาสั้นนั้นให้ประสิทธิภาพที่ดีกว่าแทนที่จะคิดว่ามันเป็นเรื่องจริงหรือไม่ มีความเป็นไปได้ที่การเพิ่มจิ๊กเกอร์ - pokery จะต้องจัดการกับกางเกงขาสั้นมากกว่า ints (ซึ่งมักเป็นประเภทที่โปรเซสเซอร์ 'ชอบใช้') อาจเป็นอันตรายต่อประสิทธิภาพการทำงานในแอปพลิเคชันเฉพาะ ไม่เสมอไป แต่คุณควรทดสอบไม่ใช่สมมติ
Neil Coffey

19

นี่เป็นคำถามที่เก่ากว่าและ pat พูดถึงตัวอักษรสั้น ๆ ฉันแค่คิดว่าฉันควรจะขยายเรื่องนี้ให้กับคนอื่น ๆ ที่จะมองสิ่งนี้ตามถนน ลองมาดูประเภท Java ดั้งเดิมอย่างละเอียด:

byte - เลขจำนวนเต็ม 8 บิต

short - เลขจำนวนเต็ม 16 บิตที่เซ็นชื่อ

int - จำนวนเต็มแบบ 32 บิต

long - จำนวนเต็มแบบ 64 บิต

char - อักขระ 16 บิต (จำนวนเต็มที่ไม่มีเครื่องหมาย)

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

char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ? 
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;

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


แก้ไข

ด้วย JDK8 มี API ใหม่สำหรับLongและIntegerให้วิธีการช่วยเหลือเมื่อทำการรักษาlongและintค่าเป็นค่าที่ไม่ได้ลงนาม

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

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


2
แต่อย่างไรก็ตามcharมีขนาดเล็กเกินไปที่จะรองรับlongเลขคณิต

3
นี่อาจเป็นข้อเสียของ Java

หวังว่าพวกเขาสนับสนุนค่า Unsigned สำหรับไบต์ ทำให้สิ่งต่าง ๆ ง่ายขึ้น
mixz

15

Java มีประเภทที่ไม่ได้ลงนามหรืออย่างน้อยหนึ่งประเภท: char เป็นคำที่ไม่ได้ลงนาม ดังนั้นข้ออ้างอะไรก็ตามที่ลูกห่านโยนขึ้นมามันเป็นแค่ความไม่รู้ของเขาว่าทำไมไม่มีประเภทอื่น ๆ ที่ไม่ได้ลงชื่อ

ประเภทสั้น: กางเกงขาสั้นที่ใช้ตลอดเวลาสำหรับมัลติมีเดีย เหตุผลก็คือคุณสามารถบรรจุตัวอย่างได้ 2 รายการในรูปแบบความยาว 32 บิตที่ไม่ได้ลงชื่อและแปลงการดำเนินการหลายอย่างเป็นเวกเตอร์ สิ่งเดียวกันกับข้อมูล 8 บิตและไบต์ที่ไม่ได้ลงนาม คุณสามารถใส่ตัวอย่าง 4 หรือ 8 ตัวอย่างในการลงทะเบียนเพื่อ vectorizing


37
ใช่ฉันแน่ใจว่าลูกห่านไม่รู้เกี่ยวกับ Java เมื่อเทียบกับคุณ
jakeboxer

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

2
มันเป็นสไตล์ที่แย่ที่จะใช้charกับอะไรก็ได้
starblue

5
@ starblue แน่นอนมันเป็น แต่มันเป็นแฮ็คที่จะหลีกเลี่ยงข้อ จำกัด ของภาษา
พื้นฐาน

14

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


12
สำหรับการมิกซ์แบบมีลายเซ็น / ไม่ได้ลงนาม: คุณอาจมีประเภทที่ไม่ได้ลงชื่อ แต่ไม่อนุญาตการมิกซ์ ยังไม่ชัดเจนว่าจำเป็นหรือไม่
sleske

2
ใน C ++ คุณต้องโรยstatic_castรอบ ๆ เพื่อผสมให้เข้ากัน มันยุ่งจริงๆ
Raedwald

4
บิตที่ 8 อยู่ตรงนั้นมันแค่พยายามซ่อนตัวเองเป็นสัญญาณ
starblue

สิ่งต่าง ๆ จะยุ่งกับประเภท 32 บิตหรือใหญ่กว่าเท่านั้น ฉันไม่เห็นเหตุผลที่ Java ไม่ควรมีการbyteลงชื่อเหมือนใน Pascal
supercat

12
มาพบฉันเมื่อคุณมีปัญหากับการประมวลผลภาพใน Java ที่คุณคาดหวังว่าไบต์จะไม่ได้ลงนาม แล้วคุณจะรู้ว่า& 0xFFการส่งเสริมการขายแบบไบต์ต่ออินทุกครั้งทำให้รหัสนั้นยุ่งยิ่งขึ้น
bit2shift

12

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

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


34
จำนวนเต็มของ Java ที่เซ็นชื่อกลิ้งไปมาด้วย ฉันไม่เห็นประเด็นของคุณ
foo

8
@foo: จำนวนเต็มที่ลงชื่อต้องได้รับขนาดใหญ่ก่อนที่จะทำให้เกิดปัญหา ในทางตรงกันข้ามใน C อาจมีปัญหาในการเปรียบเทียบจำนวนเต็มลบใด ๆ - ถึง-1- กับ quanity ที่ไม่ได้ลงนามใด ๆ - แม้แต่ศูนย์
supercat

มันแย่มากที่ Java ไม่สามารถมีประเภทที่ไม่ได้ลงนาม แต่มีชุดการแปลงและโอเปอเรเตอร์ผสม จำกัด (ค่อนข้างคล้ายกับวิธีที่ C หนึ่งสามารถเพิ่ม 5 ให้กับตัวชี้ได้ แต่ไม่มีใครเปรียบเทียบตัวชี้กับ 5) . ความคิดที่ว่าการใช้โอเปอเรเตอร์กับประเภทต่าง ๆ เมื่อมีการร่ายโดยปริยายควรบังคับให้ใช้การร่ายโดยปริยายของการร่ายนั้น (และการใช้ผลสืบเนื่องเป็นประเภทผลการทดลอง) ชวา
supercat

4
เพื่อไม่ให้พูดจาโผงผางในคำตอบของคุณ แต่ต้อง-1เป็น "ไม่ทราบ" อายุ (เป็นบทความที่แสดงให้เห็น) เป็นหนึ่งในตัวอย่างคลาสสิกของ "กลิ่นรหัส" ตัวอย่างเช่นหากคุณต้องการคำนวณ "อลิซที่เก่าแก่กว่าบ็อบมากแค่ไหน" และ A = 25 และ B = -1 คุณจะได้รับคำตอบ±26ที่ผิด การจัดการที่เหมาะสมของค่าที่ไม่รู้จักเป็นชนิดของบางอย่างOption<TArg>เมื่อจะกลับมาSome(25) - None None
bytebuster

11

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

สำหรับคำแนะนำการปฏิบัติ:

  • หากค่าของคุณจะค่อนข้างขนาดโดยพลการและไม่พอดีกับการใช้งานint longหากพวกเขาไม่พอดีกับการใช้งานlongBigInteger

  • ใช้ประเภทที่เล็กกว่าสำหรับอาร์เรย์เท่านั้นเมื่อคุณต้องการประหยัดพื้นที่

  • หากคุณต้องการบิต 64/32/16/8 ให้ใช้long/ int/ short/ byteและหยุดกังวลเกี่ยวกับบิตเครื่องหมายยกเว้นการหารการเปรียบเทียบการเปลี่ยนที่ถูกต้องและการส่ง

ดูเพิ่มเติมที่คำตอบนี้เกี่ยวกับ "การย้ายเครื่องกำเนิดตัวเลขสุ่มจาก C ถึง Java"


5
ใช่สำหรับการขยับขวาคุณต้องเลือกระหว่าง>>และ>>>สำหรับการเซ็นชื่อและไม่ได้ลงนามตามลำดับ การเลื่อนซ้ายไม่มีปัญหา
starblue

1
@starblue จริง>>>ไม่ทำงานและshort byteยกตัวอย่างเช่น(byte)0xff>>>1อัตราผลตอบแทนมากกว่า0x7fffffff 0x7fอีกตัวอย่างหนึ่ง: จะส่งผลให้byte b=(byte)0xff; b>>>=1; b==(byte)0xffแน่นอนคุณสามารถทำได้b=(byte)(b & 0xff >> 1);แต่สิ่งนี้จะเพิ่มการดำเนินการอีกหนึ่งรายการ (bitwise &)
CITBL

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

บรรทัดเปิดในคำตอบของคุณเกี่ยวกับภาวะแทรกซ้อนมากขึ้นและกำไรเล็ก ๆ น้อย ๆ เป็นสิ่งที่ผมกล่าวถึงในบทความของฉัน 6 ปีต่อมา: nayuki.io/page/unsigned-int-considered-harmful-for-java
Nayuki

1
@Nayuki บทความของคุณดีจริงๆ เพียงคำพูดเล็ก ๆ ฉันจะใช้การเพิ่ม 0x80000000 สำหรับตัวดำเนินการเปรียบเทียบแทน XOR เพราะมันอธิบายว่าทำไมมันทำงานได้มันเปลี่ยนภาคที่ต่อเนื่องกันซึ่งการเปรียบเทียบเกิดขึ้นจาก -MAXINT ถึง 0 Bitwise ผลของมันจะเหมือนกันทุกประการ
starblue

6

ด้วยJDK8มันมีการสนับสนุนบางอย่างสำหรับพวกเขา

เราอาจเห็นการสนับสนุนประเภทที่ไม่ได้ลงนามใน Java อย่างเต็มที่แม้จะมีข้อกังวลของ Gosling


12
อาคา "ดังนั้นผู้คนใช้งานจริงและเราผิดที่จะไม่รวมเข้าด้วยกันเพื่อเริ่มต้น" - แต่เรายังไม่ไว้ใจ Java devs มากนักที่จะทราบว่าตัวแปรลงชื่อหรือไม่ - ดังนั้นเราจะไม่ใช้มัน ใน VM หรือเทียบเท่ากับลูกพี่ลูกน้องที่เซ็นชื่อ
พื้นฐาน

6

ฉันรู้ว่าโพสต์นี้เก่าเกินไป อย่างไรก็ตามเพื่อความสนใจของคุณใน Java 8 และใหม่กว่าคุณสามารถใช้intชนิดข้อมูลเพื่อแสดงจำนวนเต็ม 32 บิตที่ไม่ได้ลงนามซึ่งมีค่าต่ำสุด 0 และค่าสูงสุด 2 32 −1 ใช้Integerระดับการใช้งานintประเภทข้อมูลเป็นจำนวนเต็มไม่ได้ลงนามและวิธีการคงเหมือนcompareUnsigned(), divideUnsigned()ฯลฯ ได้รับการเพิ่มIntegerระดับในการสนับสนุนการดำเนินการทางคณิตศาสตร์สำหรับจำนวนเต็มไม่ได้ลงนาม


4

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


สิ่งนี้จะดี ... ยกเว้นหลักฐานจากการสัมภาษณ์กอสลิ่งก็หมายความว่าจำนวนเต็มที่ไม่ได้ลงนาม (นอกเหนือจากchar) ถูกทิ้งไว้เพราะนักออกแบบคิดว่าพวกเขาเป็นความคิดที่ไม่ดี ... เนื่องจากเป้าหมายของภาษา
Stephen C

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

4

ฉันเคยเรียนหลักสูตร C ++ กับใครบางคนในคณะกรรมการมาตรฐาน C ++ ซึ่งบอกเป็นนัยว่า Java ทำการตัดสินใจที่ถูกต้องเพื่อหลีกเลี่ยงการมีจำนวนเต็มที่ไม่ได้ลงนามเพราะ (1) โปรแกรมส่วนใหญ่ที่ใช้จำนวนเต็มที่ไม่ได้ลงนามสามารถทำได้เช่นกัน แง่ของวิธีที่ผู้คนคิดและ (2) การใช้จำนวนเต็มที่ไม่ได้ลงนามส่งผลให้ง่ายต่อการสร้าง แต่ยากที่จะแก้ปัญหาเช่นเลขจำนวนเต็มล้นและสูญเสียบิตที่สำคัญเมื่อแปลงระหว่างประเภทที่ลงนามและไม่ได้ลงนาม หากคุณลบ 1 จาก 0 โดยใช้เลขจำนวนเต็มที่โดยไม่ตั้งใจมันมักจะทำให้โปรแกรมของคุณพังได้ง่ายขึ้นและทำให้ค้นหาข้อผิดพลาดได้ง่ายกว่าถ้ามันล้อมรอบถึง 2 ^ 32 - 1 และคอมไพเลอร์และเครื่องมือวิเคราะห์แบบคงที่ สมมติว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่ตั้งแต่คุณเลือกใช้เลขคณิตที่ไม่ได้ลงชื่อ นอกจากนี้

นานมาแล้วเมื่อหน่วยความจำถูก จำกัด และตัวประมวลผลไม่ทำงานโดยอัตโนมัติใน 64 บิตในครั้งเดียวทุกบิตนับได้มากขึ้นดังนั้นเมื่อมีการลงชื่อไบต์หรือกางเกงขาสั้นที่ไม่ได้ลงนามจริง ๆ ก็มีความสำคัญมากกว่าบ่อยครั้ง วันนี้เพียงแค่ใช้ int ที่มีการลงชื่อก็เพียงพอแล้วในเกือบทุกกรณีของการเขียนโปรแกรมปกติและหากโปรแกรมของคุณต้องการใช้ค่าที่มากกว่า 2 ^ 31 - 1 คุณก็มักจะต้องการความยาวอยู่ดี เมื่อคุณเข้าสู่ดินแดนแห่งการใช้เวลานานมันก็ยากที่จะเกิดขึ้นด้วยเหตุผลที่ว่าทำไมคุณถึงไม่สามารถทำได้ด้วยจำนวนเต็มบวก 2 ^ 63 - 1 เมื่อใดก็ตามที่เราไปถึงตัวประมวลผล 128 บิตจะมีปัญหาน้อยลง


2

คำถามของคุณคือ "ทำไม Java จึงไม่สนับสนุน ints ที่ไม่ได้ลงชื่อ"?

และคำตอบของฉันสำหรับคำถามของคุณคือ Java ต้องการให้มันเป็นประเภทดั้งเดิมทั้งหมด: ไบต์ , ถ่าน , สั้น , intและlongควรถือว่าเป็นbyte , word , dwordและqwordตามลำดับเหมือนกับในชุดประกอบและตัวดำเนินการ Java ถูกลงนามการดำเนินงานในทุกประเภทของมันดั้งเดิมยกเว้นถ่านแต่เฉพาะถ่านพวกเขาจะไม่ได้ลงชื่อ 16 บิตเท่านั้น

ดังนั้นวิธีการคงที่ควรจะเป็นการดำเนินการที่ไม่ได้ลงนามด้วยสำหรับทั้ง 32 และ 64 บิต

คุณต้องการคลาสสุดท้ายซึ่งสามารถเรียกเมธอดแบบสแตติกสำหรับผู้ที่ไม่ได้ลงชื่อดำเนินการที่

คุณสามารถสร้างคลาสสุดท้ายนี้เรียกมันว่าชื่ออะไรก็ได้ที่คุณต้องการและใช้มันเป็นวิธีการคงที่

หากคุณไม่มีความคิดเกี่ยวกับวิธีการใช้วิธีการคงที่แล้วลิงค์นี้อาจช่วยคุณได้

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

นอกจากนี้ยังแตกต่างอย่างสิ้นเชิงในชื่อของภาษาโดยวิธี

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

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

นอกจากนี้ฉันขอแนะนำให้หลีกเลี่ยงการใช้สั้น , intและยาวดั้งเดิมและใช้word , dwordและqwordตามลำดับแทนและคุณกำลังจะเรียกวิธีการคงที่สำหรับการดำเนินการที่ไม่ได้ลงชื่อและ / หรือการดำเนินการที่ลงนามแทนการใช้ตัวดำเนินการ

หากคุณกำลังจะทำการดำเนินการที่ลงนามเท่านั้นและใช้ตัวดำเนินการเฉพาะในรหัสนี่ก็โอเคที่จะใช้ประเภทดั้งเดิมเหล่านี้ สั้น , intและยาว

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

ชั้นคำถือชนิดดั้งเดิมสั้นเพียงชั้นDWORDถือชนิดดั้งเดิมintเท่านั้นและชั้นqwordถือชนิดดั้งเดิมยาวเท่านั้น ขณะนี้วิธีการที่ไม่ได้ลงนามและที่ลงนามเป็นแบบคงที่หรือไม่เป็นทางเลือกของคุณคุณสามารถใช้ในแต่ละชั้นเรียนเช่นการดำเนินการ 16 บิตทั้งที่ไม่ได้ลงชื่อและลงนามโดยให้ชื่อที่มีความหมายกับคลาสคำลงนามโดยการให้ชื่อความหมายกับคลาสdwordและการดำเนินการ 64 บิตทั้งที่ไม่ได้ลงชื่อและลงนามโดยให้ชื่อความหมายกับคลาสqword

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

หากคุณต้องการวิธีการแทนตัวดำเนินการสำหรับการดำเนินการที่ลงชื่อ 8 บิตและวิธีการสำหรับการดำเนินการที่ไม่มีเครื่องหมาย 8 บิตที่ไม่มีตัวดำเนินการเลยคุณสามารถสร้างคลาสByte (โปรดทราบว่าอักษรตัวแรก 'B' เป็นตัวพิมพ์ใหญ่ ดั้งเดิมประเภทไบต์ ) และใช้วิธีการในชั้นนี้

เกี่ยวกับการส่งผ่านค่าและผ่านการอ้างอิง:

หากฉันไม่ผิดเช่นใน C # วัตถุดั้งเดิมจะถูกส่งผ่านตามค่าตามธรรมชาติ แต่คลาสอ็อบเจ็กต์จะถูกส่งผ่านโดยการอ้างอิงตามธรรมชาติดังนั้นหมายความว่าวัตถุประเภทByte , word , dwordและqwordจะถูกส่งผ่านโดยการอ้างอิงไม่ใช่ตามค่า โดยค่าเริ่มต้น. ฉันหวังว่า Java มีstructวัตถุเป็น C # มีดังนั้นสิ่งไบต์ , คำ , DWORDและqwordสามารถดำเนินการให้เป็นstructแทนระดับดังนั้นโดยค่าเริ่มต้นพวกเขาถูกส่งผ่านโดยค่าและไม่ใช่โดยการอ้างอิงโดยค่าเริ่มต้นเช่นวัตถุ struct ใด ๆ ใน C # เช่นประเภทดั้งเดิมจะถูกส่งผ่านโดยค่าและไม่โดยอ้างอิงโดยค่าเริ่มต้น แต่เพราะ Java นั้นเลวร้ายยิ่งกว่า C # และเรา เพื่อจัดการกับสิ่งนั้นมีเพียงคลาสและอินเตอร์เฟสที่ถูกส่งผ่านโดยการอ้างอิงไม่ใช่ตามค่าเริ่มต้น ดังนั้นหากคุณต้องการผ่านByte , word , dwordและ qwordตามค่าและไม่ใช่โดยการอ้างอิงเช่น object class อื่น ๆ ใน Java และใน C # คุณจะต้องใช้ตัวสร้าง copy และนั่นคือมัน

นั่นเป็นทางออกเดียวที่ฉันคิดได้ ฉันแค่หวังว่าฉันจะสามารถพิมพ์ชนิดดั้งเดิมเป็น word, dword และ qword ได้ แต่ Java ไม่รองรับ typedef หรือใช้เลยเหมือน C # ที่รองรับใช้ซึ่งเทียบเท่ากับ typedef ของ C

เกี่ยวกับผลลัพธ์:

สำหรับลำดับของบิตเดียวกันเดียวกันคุณสามารถพิมพ์ได้หลายวิธี: ในฐานะไบนารีเป็นทศนิยม (เช่นความหมายของ% u ใน C printf) เป็นฐานแปด (เช่นความหมายของ% o ใน C printf) เป็นเลขฐานสิบหก (เช่น ความหมายของ% x ใน C printf) และเป็นจำนวนเต็ม (เช่นความหมายของ% d ใน C printf)

โปรดทราบว่า C printf ไม่ทราบชนิดของตัวแปรที่ส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันดังนั้น printf จึงรู้ประเภทของตัวแปรแต่ละตัวจากออบเจ็กต์ char * ที่ส่งไปยังพารามิเตอร์แรกของฟังก์ชัน

ดังนั้นในแต่ละชั้นเรียน: Byte , word , dwordและqwordคุณสามารถใช้วิธีการพิมพ์และรับฟังก์ชั่นการทำงานของ printf แม้ว่าการลงนามในชั้นเรียนแบบดั้งเดิมจะยังคงไม่ได้ลงนามโดยทำตามขั้นตอนวิธีที่เกี่ยวข้อง การดำเนินการทางตรรกะและ shift เพื่อรับตัวเลขเพื่อพิมพ์ไปยังเอาต์พุต

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

นั่นคือทั้งหมดที่ฉันสามารถตอบคำถามของคุณและแนะนำคุณ


MASM (Microsoft แอสเซมเบลอร์) และ Windows กำหนด BYTE, WORD, DWORD, QWORD เป็นประเภทที่ไม่ได้ลงนาม สำหรับ MASM, SBYTE, SWORD, SDWORD, SQWORD นั้นเป็นประเภทที่ลงนามแล้ว
rcgldr

1

เพราะ unsignedประเภทคือความชั่วร้ายบริสุทธิ์

ความจริงที่ว่าใน C unsigned - intผลิตunsignedความชั่วร้ายมากยิ่งขึ้น

นี่คือภาพรวมของปัญหาที่เผาฉันมากกว่าหนึ่งครั้ง:

// We have odd positive number of rays, 
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );

// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
    // Compute the angle between nth ray and the middle one.
    // The index of the middle one is (rays.size() - 1) / 2,
    // the rays are evenly spaced at angle delta, therefore
    // the magnitude of the angle between nth ray and the 
    // middle one is: 
    double angle = delta * fabs( n - (rays.size() - 1) / 2 ); 

    // Do something else ...
}

คุณสังเกตเห็นข้อผิดพลาดหรือยัง ฉันสารภาพฉันเห็น แต่หลังจากก้าวเข้ามาพร้อมกับเครื่องมือดีบั๊กแล้ว

เพราะnเป็นประเภทที่ไม่ได้ลงชื่อsize_tการแสดงออกทั้งประเมินเป็นn - (rays.size() - 1) / 2 unsignedการแสดงออกนั้นตั้งใจจะเป็นตำแหน่งที่เซ็นชื่อของnรังสีดวงที่หนึ่งจากจุดกึ่งกลาง: รังสีดวงที่ 1 จากจุดกึ่งกลางทางด้านซ้ายจะมีตำแหน่ง -1, อันที่ 1 ทางด้านขวาจะมีตำแหน่ง +1 เป็นต้น รับค่า abs และคูณด้วยdeltaมุมฉันจะได้มุมระหว่างnเรย์ th กับอันตรงกลาง

น่าเสียดายสำหรับฉันนิพจน์ด้านบนมีสิ่งชั่วร้ายที่ไม่ได้ลงนามและแทนที่จะประเมินให้พูดว่า -1 จะได้รับการประเมินเป็น 2 ^ 32-1 การแปลงที่ตามมาเป็นdoubleปิดผนึกข้อผิดพลาด

หลังจากบั๊กหรือสองอันเกิดจากการใช้unsignedเลขคณิตในทางที่ผิดจะต้องเริ่มสงสัยว่าบิตพิเศษที่ได้รับนั้นมีค่ามากหรือไม่ ฉันพยายามเท่าที่จะทำได้เพื่อหลีกเลี่ยงการใช้unsignedประเภทใด ๆในการคำนวณแม้ว่าจะยังคงใช้สำหรับการดำเนินการที่ไม่ใช่ทางคณิตศาสตร์เช่นไบนารีมาสก์


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

@supercat: หากunsignedได้รับการแปลงintในทุกการดำเนินการสิ่งที่ใช้unsigned? shortมันจะไม่ได้มีความแตกต่างจากการทำงานใด ๆ และถ้าคุณแปลงเป็นintเฉพาะการดำเนินการแบบผสมเช่นunsigned+intหรือunsigned+floatจากนั้นคุณยังคงมีปัญหา((unsigned)25-(unsigned)30)*1.0 > 0ซึ่งเป็นสาเหตุสำคัญของunsignedข้อบกพร่องที่เกี่ยวข้อง
ไมเคิล

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

3
ฉันไม่ชอบคำตอบนี้เพราะใช้อาร์กิวเมนต์ "จำนวนเต็มที่ไม่ได้ลงชื่อเป็นสิ่งชั่วร้ายและไม่ควรมีอยู่เพราะพวกเขาไม่สามารถลงชื่อได้" ทุกคนที่พยายามลบออกจากจำนวนเต็มที่ไม่มีเครื่องหมายควรทราบสิ่งนี้อยู่แล้ว และสำหรับความสามารถในการอ่าน C ไม่เป็นที่รู้จักอย่างแน่นอนว่าเป็นเรื่องง่ายที่จะติดตาม นอกจากนี้อาร์กิวเมนต์ (กึ่ง -) "บิตเพิ่มเติมไม่คุ้มกับปัญหาเพิ่มเติม" ก็อ่อนแอเช่นกัน การจัดการข้อผิดพลาดแทนexit(1);'คุ้มค่ากับปัญหาพิเศษ' จริงๆหรือไม่? ไม่สามารถเปิดไฟล์ขนาดใหญ่ที่คุ้มค่ากับการรักษาความปลอดภัยที่โปรแกรมเมอร์ Java ที่มีประสบการณ์น้อยจะไม่ทำให้เกิดความวุ่นวายunsignedใช่หรือไม่?
yyny

2
เพียง n - (rays.size() - 1) / 2แต่สิ่งที่ชั่วร้ายที่ฉันเห็นในรหัสนี้ คุณควรวงเล็บผู้ประกอบการไบนารีเสมอเพราะผู้อ่านรหัสไม่จำเป็นต้องคิดอะไรเกี่ยวกับลำดับของการดำเนินการในโปรแกรมคอมพิวเตอร์ เพียงเพราะเราพูดตามอัตภาพว่า a + b c = a + (b c) ไม่ได้หมายความว่าคุณสามารถสันนิษฐานได้เมื่ออ่านโค้ด นอกจากนี้การคำนวณควรกำหนดนอกลูปเพื่อให้สามารถทดสอบได้โดยไม่ต้องมีลูป นี่เป็นข้อบกพร่องที่ทำให้แน่ใจว่าประเภทของคุณเข้าแถวแทนที่จะเป็นปัญหาจำนวนเต็มที่ไม่ได้ลงนาม ใน C ขึ้นอยู่กับคุณเพื่อให้แน่ใจว่าประเภทของคุณเข้าแถวกัน
Dmitry

0

มีอัญมณีบางอย่างในข้อมูลจำเพาะของ 'C' ที่ Java ได้ลดลงเนื่องจากเหตุผลที่สามารถนำไปใช้งานได้จริง แต่จะค่อย ๆ คลานกลับไปตามความต้องการของนักพัฒนา

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

ฉันเดาว่าถ้ามีใครจะได้รับ Dennis Ritchie ปรับเปลี่ยนอัตตาเพื่อให้คำแนะนำกับทีมออกแบบของ Gosling มันจะแนะนำให้ Signed เป็น "ศูนย์ที่ไม่มีที่สิ้นสุด" เพื่อให้คำขอออฟเซ็ตออฟที่อยู่ทั้งหมดจะเพิ่มขนาด ALGEBRAIC RING

ด้วยวิธีนี้การชดเชยออฟเซตที่อาร์เรย์ไม่สามารถสร้าง SEGFAULT ได้ ตัวอย่างเช่นในคลาสที่ห่อหุ้มซึ่งฉันเรียก RingArray ของคู่ที่ต้องการพฤติกรรมที่ไม่ได้ลงนาม - ในบริบท "วงหมุนด้วยตนเอง":

// ...
// Housekeeping state variable
long entrycount;     // A sequence number
int cycle;           // Number of loops cycled
int size;            // Active size of the array because size<modulus during cycle 0
int modulus;         // Maximal size of the array

// Ring state variables
private int head;   // The 'head' of the Ring
private int tail;   // The ring iterator 'cursor'
// tail may get the current cursor position
// and head gets the old tail value
// there are other semantic variations possible

// The Array state variable
double [] darray;    // The array of doubles

// somewhere in constructor
public RingArray(int modulus) {
    super();
    this.modulus = modulus;
    tail =  head =  cycle = 0;
    darray = new double[modulus];
// ...
}
// ...
double getElementAt(int offset){
    return darray[(tail+modulus+offset%modulus)%modulus];
}
//  remember, the above is treating steady-state where size==modulus
// ...

RingArray ด้านบนจะไม่ 'รับ' จากดัชนีลบแม้ว่าผู้ร้องขอที่เป็นอันตรายจะพยายาม โปรดจำไว้ว่ายังมีคำขอที่ถูกต้องตามกฎหมายจำนวนมากสำหรับการขอค่าดัชนี (เชิงลบ) ก่อนหน้านี้

หมายเหตุ:% โมดูลัสด้านนอกยกเลิกการอ้างอิงคำร้องขอที่ถูกกฎหมายในขณะที่% โมดูลัสด้านในออกมาพูดอาฆาตพยาบาทจากเชิงลบมากกว่าโมดูลัส หากสิ่งนี้เคยปรากฏใน Java + .. + 9 || 8+ .. + spec แล้วปัญหาจะกลายเป็น 'โปรแกรมเมอร์ที่ไม่สามารถ "หมุนตัวเอง" FAULT' อย่างแท้จริง

ฉันแน่ใจว่า Java ที่เรียกว่า 'การขาด' ที่ไม่ได้ลงชื่อซึ่งสามารถถูกสร้างขึ้นโดยใช้หนึ่งซับด้านบน

PS: เพียงเพื่อให้บริบทข้างต้น RingArray แม่บ้านนี่คือการดำเนินการของผู้สมัครเพื่อให้ตรงกับการดำเนินงานองค์ประกอบ 'รับ' ข้างต้น:

void addElement(long entrycount,double value){ // to be called only by the keeper of entrycount
    this.entrycount= entrycount;
    cycle = (int)entrycount/modulus;
    if(cycle==0){                       // start-up is when the ring is being populated the first time around
        size = (int)entrycount;         // during start-up, size is less than modulus so use modulo size arithmetic
        tail = (int)entrycount%size;    //  during start-up
    }
    else {
        size = modulus;
        head = tail;
        tail = (int)entrycount%modulus; //  after start-up
    }
    darray[head] = value;               //  always overwrite old tail
}

-2

ฉันนึกถึงผลข้างเคียงที่โชคร้ายอย่างหนึ่ง ในฐานข้อมูลแบบฝังของจาวาจำนวนรหัสที่คุณสามารถมีได้ด้วยฟิลด์รหัส 32 บิตคือ 2 ^ 31 ไม่ใช่ 2 ^ 32 (~ 2 พันล้านไม่ใช่ ~ 4 พันล้าน)


1
เขาอาจคิดถึงอาร์เรย์และไม่สามารถใช้จำนวนเต็มลบเป็นดัชนีได้ อาจ.
SK9

2
เมื่อเขตข้อมูลที่เพิ่มขึ้นอัตโนมัติในฐานข้อมูลล้นพวกเขามักจะไป wacko
Joshua

-8

เหตุผลที่ IMHO นั้นเป็นเพราะพวกเขา / ขี้เกียจเกินกว่าที่จะใช้ / แก้ไขข้อผิดพลาดนั้น การแนะนำว่าโปรแกรมเมอร์ C / C ++ ไม่เข้าใจโครงสร้างที่ไม่ได้ลงนาม, union, union, bit flag ... เป็นเรื่องที่ผิดปกติ

อีเธอร์ที่คุณกำลังพูดคุยกับโปรแกรมเมอร์พื้นฐาน / bash / java ที่กำลังจะเริ่มเขียนโปรแกรม la C โดยไม่ต้องมีความรู้ภาษานี้จริง ๆ หรือคุณแค่พูดออกมาจากใจของคุณเอง ;)

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

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

กระแสตรง


34
เพียงเพื่อ kicks, Google วลี "ห่วงหมุนตัวเอง" เห็นได้ชัดว่าเดนิสเป็นคนเดียวในโลกที่สมควรจะเรียกตัวเองว่าโปรแกรมเมอร์ :-)
สตีเฟ่นซี

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