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


10

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

นี่คือสคีมาที่สามารถแสดงตัวเลขตั้งแต่ 0 ถึง 255:

ใช้ไบต์แรกของที่เก็บข้อมูล (ที่อยู่ 0) เพื่อเก็บจำนวนเต็ม

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

นี่คือสคีมาอีกอย่างที่ควรจะสามารถทำงานได้ แต่มันอาจยังห่างไกลจากประสิทธิภาพ

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

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

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


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

1
@ user16764 คุณหมายถึงตัวแปรเลขจำนวนเต็ม 64 บิตเดียวหรือไม่ แน่นอนว่ามันจะไม่ทำงาน: ถ้าคน 6 ล้านคนบริโภค 1 ล้าน UUID ต่อวินาทีมันจะกินเวลานานกว่าหนึ่งเดือน
Dmitri Shuralyov

1
และใช้เวลานานเท่าใดกับเครื่อง 128- บิต?
user16764

2
แนวคิดในRFC 2550ซึ่งเป็นตัวแทนของ ASCII ที่เรียงลำดับตามคำศัพท์สำหรับเลขจำนวนเต็มบวกที่มีขนาดใหญ่โดยพลอาจปรับให้เข้ากับสิ่งนี้ได้ ในที่สุดมันจะแบ่งออกเป็นเซ็กเมนต์เอกนารีซึ่งเข้ารหัสความยาวของเซกเมนต์ฐาน 26 ซึ่งเข้ารหัสความยาวของเซกเมนต์ฐาน 10 ส่วนฐานสองหลังหลังมีส่วนเกี่ยวข้องกับการเป็นตัวแทน ASCII มากกว่าสิ่งใดที่เป็นพื้นฐานของโครงการ
Random832

1
สมมติว่าคุณสร้างหมายเลข 128 บิตตามลำดับ: ถ้าเราจำกัดความสามารถในการคำนวณของคอมพิวเตอร์ทุกเครื่องโดยให้คอมพิวเตอร์ petaflop ทุกคนมันจะใช้เวลา 9 ล้านปีก่อนที่ตัวเลขเหล่านี้จะหมด หากในทางกลับกันมนุษย์ทุกคนจะสุ่มสร้างตัวเลข 600 ล้าน 128 บิตมีโอกาส 50% ที่พวกเขาจะสร้าง 1 ซ้ำ ดีพอสำหรับคุณหรือไม่ ( en.wikipedia.org/wiki/Universally_unique_identifier ) หากไม่ใช้ 256 บิตจะคูณทั้งตัวเลขเหล่านี้ด้วย 2 ^ 128 = 3.4 * 10 ^ 38 ซึ่งเป็นมากกว่าสี่เหลี่ยมจัตุรัสของจักรวาลในไม่กี่วินาที
อเล็กซ์สิบบริงค์

คำตอบ:


13

วิธีการที่ผมเคยใช้: นับจำนวนชั้นนำ 1 nบิตกล่าวว่า ขนาดของตัวเลขนั้นเป็น 2 ^ n ไบต์ (รวมถึงส่วนนำ 1 บิต) รับบิตหลังจาก 0 บิตแรกเป็นจำนวนเต็มและเพิ่มค่าสูงสุด (บวกหนึ่ง) ที่สามารถแทนด้วยตัวเลขโดยใช้การเข้ารหัสนี้ในไบต์ 2 ^ (n-1)

ดังนั้น,

                  0 = 0b00000000
                   ...
                127 = 0b01111111
                128 = 0b1000000000000000
                   ...
              16511 = 0b1011111111111111
              16512 = 0b11000000000000000000000000000000
                   ...
          536887423 = 0b11011111111111111111111111111111
          536887424 = 0b1110000000000000000000000000000000000000000000000000000000000000
                   ...
1152921505143734399 = 0b1110111111111111111111111111111111111111111111111111111111111111
1152921505143734400 = 0b111100000000000000000000000000000000000000000000 ...

ชุดรูปแบบนี้อนุญาตให้แสดงค่าที่ไม่เป็นลบใด ๆ ในวิธีเดียว

(เท่ากันใช้จำนวนนำ 0 บิต)


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

2
ฉันเขียนบทความเชิงลึกเพิ่มเติมพร้อมตัวอย่างการพิจารณาและการออกแบบ
retracile

10

มีทฤษฎีมากมายตามที่คุณพยายามจะทำ ลองดูที่หน้า wiki เกี่ยวกับรหัสสากล - มีรายการวิธีการเข้ารหัสจำนวนเต็มค่อนข้างครบถ้วน (บางวิธีใช้ในทางปฏิบัติจริง)

ในการบีบอัดข้อมูลรหัสสากลสำหรับจำนวนเต็มเป็นรหัสนำหน้าที่จับคู่จำนวนเต็มบวกกับไบนารี codewords

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


ขอบคุณสำหรับสิ่งนั้นที่น่าสนใจมาก ฉันต้องการทำเครื่องหมายว่าเป็นคำตอบที่ยอมรับ แต่ใช้สถานที่ที่ 2 นี่เป็นคำตอบที่ดีมากจากมุมมองทางทฤษฎี IMO
Dmitri Shuralyov

4

ให้จำนวนผู้นำ 1 บวก 0 แรกเป็นขนาด (sizeSize) ของขนาดตัวเลข (numSize) เป็นบิต numSize เป็นเลขฐานสองที่ให้ขนาดของการแทนตัวเลขเป็นไบต์รวมถึงบิตขนาด บิตที่เหลือคือจำนวน (NUM) ในไบนารี สำหรับชุดเลขจำนวนเต็มบวกนี่คือตัวอย่างตัวเลขบางตัวอย่าง:

Number              sizeSize  numSize    num
63:                 0 (1)     1 (1)      111111
1048575:            10 (2)    11 (3)     1111 11111111 11111111
1125899906842623:   110 (3)   111 (7)    11 11111111 11111111 11111111 11111111 11111111 11111111
5.19.. e+33:        1110 (4)  1111 (15)  11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

4

วิธีการเกี่ยวกับ: หนึ่งไบต์สำหรับความยาวแล้ว n ไบต์สำหรับจำนวน (ไบต์ที่สำคัญน้อยที่สุดก่อน) ทำซ้ำความยาว + หมายเลขตราบใดที่ความยาวก่อนหน้าคือ 255

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


fNek: ไม่มีขีด จำกัด บน ตัวอย่างเช่นหากคุณต้องการ 513 ไบต์สำหรับตัวเลขลำดับไบต์คือ [255, b0, ... , b255,255, b256, ... , b511,2, b512, b513]
281377

ขอโทษ ควรเรียนรู้การอ่านให้ละเอียดยิ่งขึ้น
fNek

3

ทำไมไม่ใช้เพียง 7 บิตจากแต่ละไบต์และใช้บิตที่ 8 เพื่อระบุว่ามีอีกหนึ่งไบต์ที่ต้องติดตาม ดังนั้น 1-127 จะเป็นหนึ่งไบต์, 128 จะแทนด้วย 0x80 0x01, เป็นต้น


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

3
ดังนั้นคุณต้องสแกนหมายเลขสองครั้งเพื่อทำสำเนามันคืออะไร ถ้าฉันสามารถรอเลขจำนวนมากได้ฉันสามารถรอได้สองครั้ง
รัสเซล Borogove

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

3

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

ปัญหาเกี่ยวกับการใช้ 0xFFFF เพื่อแสดงถึงการสิ้นสุดของหมายเลขแฟล็กคือการทำให้การเข้ารหัสหมายเลขของคุณมีประสิทธิภาพน้อยลงเมื่อตัวเลขมีขนาดใหญ่ อย่างไรก็ตามดูเหมือนว่ารูปแบบ UUID ของคุณทำให้ปัญหานี้แย่ลง แทนที่จะข้ามหนึ่งใน 256 ไบต์คุณข้ามพื้นที่ UUID ไปหมดแล้ว ประสิทธิภาพของการคำนวณ / การรับรู้ (แทนที่จะเป็นที่ว่าง) ขึ้นอยู่กับคอมพิวเตอร์เชิงทฤษฎีของคุณ (ซึ่งฉันคิดว่าคุณมีถ้าคุณกำลังพูดถึงอนันต์) สำหรับ TM ด้วยเทปและคอนโทรลเลอร์สถานะอัน จำกัด รูปแบบ UUID ใด ๆ นั้นเป็นไปไม่ได้ที่จะปรับขนาดได้อย่างมีประสิทธิภาพ หากคุณไม่ได้รับตัวควบคุม Finite State สิ่งนี้อาจใช้ไม่ได้ แต่คุณต้องพิจารณาว่าบิตไปในกระบวนการถอดรหัส / การรับรู้

หากคุณต้องการประสิทธิภาพที่ดีกว่า 1 จาก 256 ไบต์คุณสามารถใช้ความยาวบิตใด ๆ ของ 1s ที่คุณจะใช้สำหรับรูปแบบ UUID ของคุณ นั่นคือ 1 ใน 2 ^ บิตที่ไม่มีประสิทธิภาพ

โปรดทราบว่ามีรูปแบบการเข้ารหัสอื่น ๆ การเข้ารหัสไบต์ด้วยตัวคั่นเกิดขึ้นได้ง่ายที่สุดในการใช้


2

ฉันขอแนะนำให้มีอาร์เรย์ของไบต์ (หรือ ints หรือ longs) และเขตข้อมูลความยาวที่ระบุว่านานแค่ไหนจำนวน

นี่คือวิธีการประมาณที่ใช้โดยของ Java BigInteger พื้นที่ที่อยู่ที่เป็นไปได้มีขนาดใหญ่พอที่จะให้ UUID ที่แตกต่างกันไปสำหรับอะตอมแต่ละอะตอมในจักรวาล :-)

หากคุณไม่มีเหตุผลที่ดีที่จะทำอย่างอื่นฉันขอแนะนำให้ใช้ BigInteger โดยตรง (หรือเทียบเท่าในภาษาอื่น ๆ ) ไม่จำเป็นต้องบูรณาการล้อจำนวนมาก ....


คุณไม่สามารถเข้ารหัสความยาวของอาร์เรย์ได้เมื่อจำนวนของฟิลด์สามารถไม่มีที่สิ้นสุด
Slawek

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

@Slawek: จริง แต่สำหรับกรณีการใช้งาน OP อธิบายไว้ (เช่น UUIDs) BigInteger นั้นไม่มีที่สิ้นสุดอย่างมีประสิทธิภาพ คุณไม่สามารถเข้ารหัสข้อมูลที่ไม่มีที่สิ้นสุดในคอมพิวเตอร์เครื่องใดที่มีหน่วยความจำขนาด จำกัด อยู่แล้วดังนั้น BigInteger จึงดีพอ ๆ กับสิ่งอื่น ๆ ที่คุณมีโอกาสประสบความสำเร็จ
mikera

2

ก่อนอื่นขอขอบคุณทุกคนที่ให้คำตอบสำหรับคำถามที่ค่อนข้างคลุมเครือและเป็นนามธรรมของฉัน

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

ในขณะที่บางคนชี้ให้เห็นว่าการใช้จำนวนเต็มขนาด 64/128/256 บิตจะช่วยให้คุณมีพื้นที่ขนาดใหญ่มากสำหรับ UUID เห็นได้ชัดว่ามันไม่มีที่สิ้นสุด แต่ ...

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

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

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