เคล็ดลับทั่วไปสำหรับการแสดงจำนวนมาก


21

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

อะไรทั่วไป1คุณเคล็ดลับสำหรับการเป็นตัวแทนมีตัวเลขยาวรัดกุมในรหัส?

กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ


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




ฉันเห็นบางคนเข้าใจผิดคำถาม - บางทีชื่อควรบอกว่านี่เป็นเรื่องเกี่ยวกับการเล่นกอล์ฟ
Ørjan Johansen

คำตอบ:


15

ระวังหมายเลขพิเศษ

บางภาษามีฟังก์ชั่นในตัวสำหรับกำลังสองการยกกำลังด้วยฐาน 2, n- th ไพรม์, แฟคทอเรียลหรือขั้นตอนอื่น ๆ ที่สามารถสร้างจำนวนมากได้ ตรวจสอบว่าคุณมีหมายเลขอยู่ในหมวดหมู่ใด ๆ หรือไม่

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


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

7
+1 สำหรับ "จำนวนที่มากขึ้น" - หาก1.01e6การทำซ้ำเพียงพอ1e7บันทึก 3 ไบต์โดยเสียค่าใช้จ่ายในการรัน
Chris H

13

ใช้ตัวดำเนินการบูลีน bitwise

บางภาษามีระดับบิตและ AND, หรือ, แฮคเกอร์และบางครั้งก็ไม่

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

ตัวอย่างเช่น2147483722คือ 10 ไบต์ แต่2<<30^74(2 ^ 31 bitwise-XORed กับ 74) มีเพียง 8


3
ตัวดำเนินการแบบกะสามารถถูกแทนที่ด้วยการยกกำลังหากภาษานั้นมีตัวดำเนินการนั้น (เช่นbc) และ XOR ไม่มีประโยชน์มากกว่า+และ-ในกรณีนี้ xor และ add ให้ผลเหมือนกัน แต่ในทุกกรณีมีจำนวนเต็มซึ่งสามารถเพิ่มหรือลบเพื่อสร้างผลลัพธ์เดียวกันกับ xor ด้วยจำนวนเต็มและส่วนเพิ่มเติมคือ ไม่ใหญ่และบางครั้งก็สั้น
2560

3
@rici จริงถ้าจำนวนเต็มทั้งหมดเขียนเป็นทศนิยมแบบง่าย ๆ แต่เป็นไปได้ว่าจำนวนเต็มที่ใช้กับ xor นั้นสามารถย่อให้สั้นลงได้ด้วยวิธีที่จำนวนเต็มที่ใช้กับบวกหรือลบไม่สามารถคิด1e9^2e9ได้
hvd

2
@rici คุณจะ9<<49^7<<19ใช้การเพิ่มแทน xor ได้อย่างไร
L3viathan

2
@rici ไม่ฉันหมายถึงสิ่งที่ฉันเขียน มันประเมิน1286561280ใน JavaScript และ Perl (และภาษาอื่น ๆ ที่อาจจะ) และมันก็แสดงออกสั้นในการผลิตมูลค่ากว่าเทียบเท่าใช้หรือ+ -
hvd

@hvd: ตกลงจุดที่ใช้
2560

11

ใช้สตริงเพื่อหมายเลขซ้ำ

สำหรับตัวเลขที่ซ้ำซ้อนมากในธรรมชาติคุณสามารถใช้ Strings และส่งไปยัง Integer ตัวอย่างเช่นใน JavaScript

+"1".repeat(100) // returns 100 1s (saves 84 bytes!)

2
หรือคุณอาจใช้เศษส่วนที่มีขนาดใหญ่มาก1e100/9ในกรณีนี้
ETHproductions

11

ใช้สัญลักษณ์ทางวิทยาศาสตร์

สัญลักษณ์ทางวิทยาศาสตร์สามารถบันทึกไบต์ในกรณีของตัวเลขที่ยาว ตัวอย่างเช่น:

3564e-8 // returns 0.00003564 (saves 3 bytes!)

3
ทำไมไม่ใช้3564e-8ในกรณีเช่นนั้น?
Joey

@ โจอี้ใช่แน่นอน! ขอขอบคุณ! :)
Arjun

จริงอยู่ที่คุณสามารถเขียนหมายเลขอื่น ๆ ได้เช่น.00003564กันซึ่งสั้นกว่าอีกหนึ่งไบต์
Joey

@Joey ไม่ใช่ทุกภาษาที่ทำดังนั้นฉันจะไม่แก้ไขสิ่งต่อไปนี้
Arjun

เป็นความตั้งใจหรือไม่ที่ 3564 (ซ้าย) กลายเป็น 354 (ขวา) หรือพิมพ์ผิด?
Erik

10

ค้นหาหมายเลขอื่นเพื่อใช้แทน

สิ่งนี้อาจฟังดูเหมือนไม่ใช่คำตอบ แต่ไม่ชัดเจนเสมอไปว่าจำนวนที่มากขึ้นสามารถคำนวณได้ด้วยรหัสที่สั้นกว่า ตัวอย่างที่ผมจำได้ว่าเป็นขาออกสำเนา googol ของสตริงที่คำตอบที่ชัดเจนต้องใช้การคำนวณ 10 100 ตามที่ปรากฎการคำนวณหลาย ๆ 10 100นำไปสู่การที่ถูกต้องเท่ากัน แต่ในบางภาษาคำตอบที่สั้นกว่า คำตอบที่เดนนิสมีใช้ 100 100 , การใช้งานของตัวเอง 250 255


4
อีกตัวอย่างหนึ่งของเรื่องนี้คือ CJam ที่คุณสามารถรับการประทับเวลาปัจจุบันได้esถ้าคุณต้องการจำนวนมาก แต่ไม่สนใจค่าของมัน (หรือว่ามันจะเหมือนกันเสมอ)
Martin Ender

10

การบีบอัดฐาน

รหัสการคลายการบีบอัดฐานอาจมีความซับซ้อนพอสมควร แต่ถ้าคุณมีจำนวนมหาศาลจริง ๆ บางครั้งมันสามารถช่วยบีบอัดในบางฐานที่สูงกว่า 10

นอกจากนี้ยังช่วยในบางภาษารหัสการบีบอัดฐานง่ายมาก ตัวอย่างเช่น PHP มีbase64_decode(_), Python มีint(_,36), JavaScript มีparseInt(_,36)และหลายภาษาที่เล่นกอล์ฟมีฐานการบีบอัดในตัว ตัวอย่างเช่นใน CJam:

"+ÜTbô±"256b

สิ่งนี้มี unprintable ลองออนไลน์!

อัตราผลตอบแทนนี้:

12345678987654321

9

ใช้เศษส่วนเลขชี้กำลังสำหรับจำนวนซ้ำจำนวนมาก

สมมติว่าคุณต้องการสร้างจำนวนที่ทำจาก 100 1 คุณสามารถใช้int("1"*100), +"1".repeat(100)ฯลฯ แต่คุณยังสามารถใช้ประโยชน์จากความจริงที่ว่ามันเป็นมากใกล้เคียงกับ

1e100/9

วิธีนี้ทำงานได้ดีที่สุดสำหรับตัวเลขซ้ำ ๆ เช่นตัวเลขที่ทำจากตัวเลขหลักเดียว ตัวเลขสองหลักซ้ำยังใช้งานได้ดี:

12e100/99  // Generates 121212121212... (100 digits)

ในบางครั้งคุณจะพบลวดลายแปลก ๆ บางอย่างซึ่งยังสามารถใช้แทนวิธีนี้ได้ค่อนข้างแน่น หากคุณต้องการint("123456790"*11)เช่น:

1e100/81

ระวังด้วย: ตัวเลขเช่นint("1234567890"*10)ไม่มีการแทนค่าแบบง่าย


9

ใช้ปุ่ม Shift ซ้ายซ้ายเพื่อยกกำลัง 2

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

แต่คุณสามารถบันทึกไบต์บางอย่างเมื่อคุณจำเป็นต้องเพิ่ม 2 ถึงอำนาจnโดยใช้ผู้ประกอบการกดปุ่ม Shift Bitwise ซ้ายเป็น<< 1<<nโปรดทราบว่าการทำเช่นนี้จะช่วยให้คุณประหยัดได้เพียงไบต์เท่านั้นหากnมากกว่าหรือเท่ากับ 17 อย่างไรก็ตามสิ่งนี้จะช่วยให้คุณประหยัดไบต์ได้เสมอหากnเป็นแบบไดนามิก ตัวอย่างน้อย:

1<<2 // returns 4 (3 bytes more :( )
1<<3 // returns 8 (3 bytes more :( )
1<<6 // returns 64 (2 bytes more :( )
1<<14 // returns 16384 (no bytes saved)
1<<17 // returns 131072 (saves 1 byte!)
1<<18 // returns 262114 (saves 1 byte!)

4
โปรดทราบว่าคุณสามารถใช้ค่าอื่นแทน 1 8<<9 // 4096เพื่อให้เราสามารถเพิ่มได้ถึง99<<616 ไบต์ซึ่งเท่ากับ6,917,529,027,641,081,856ประหยัด 13 ไบต์!
Draco18s

@ Draco18s ใช่และมันครอบคลุมที่นี่
Arjun

นั่นครอบคลุมอีกหนึ่งตัวดำเนินการระดับบิตบูลีน ใช่มันมีการเลื่อนบิตด้วยเช่นกัน แต่มันกำลังพูดถึงการใช้ตัวเลขสองตัวใหญ่กับ XOR และได้ตัวเลขที่สาม
Draco18s

7

ทฤษฏีส่วนที่เหลือของจีน

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

เลือกจำนวนเต็มที่ค่อนข้างสำคัญจำนวนคู่ m i > = 2 และคุณสามารถแสดงจำนวนมากจาก 0 ถึง lcm (m 1 , m 2 , ... , m i ) -1

ตัวอย่างเช่นฉันเลือก 2, 3, 5, 11, 79, 83, 89, 97 จากนั้นฉันสามารถแสดงหมายเลขน้อยกว่า 18680171730 โดยไม่ซ้ำกัน 10000000000 (1e10) สามารถแสดงเป็น 0,1,0,1,38,59,50,49 (1e10 mod 2, 3 ... , 97) ซึ่งไม่จำเป็นต้องแสดงเป็นคลาส / โครงสร้าง Big Integer พิเศษซึ่งอาจประหยัด บางไบต์ในภาษาการเขียนโปรแกรมบางอย่าง

การเพิ่มและการลบสามารถทำได้โดยตรงโดยใช้การเป็นตัวแทนนี้ ตัวอย่าง:

(0,1,0,1,38,59,50,49)+(0,2,0,6,23,20,16,53) = 1e10 + 5000 
                                            = (0+0 mod 2, 1+2 mod 3, 0+0 mod 5, 1+6 mod 11, 38+23 mod 79, 59+20 mod 83, 50+16 mod 89, 49+53 mod 97)

1
สนใจที่จะอธิบายอย่างละเอียดเกี่ยวกับที่?
Skidsdev

@Mayube ฉันได้เพิ่มคำอธิบายบางอย่าง แต่ฉันสงสัยว่ามันไร้ประโยชน์ในกรณีส่วนใหญ่
Aria Axe

1
มันคือ "ทฤษฎีบทส่วนที่เหลือ"
Ørjan Johansen

6

ใช้การเสริมสาย (ที่เป็นไปได้)

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


ตัวอย่าง

วิธีสร้างหมายเลข1111111111111111111111112(25 ไบต์) ใน JavaScript (ES8):

+"2".padStart(25,1) // 19 bytes

3

ใช้เลขชี้กำลัง

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

ตัวอย่าง

จำนวนเต็มปลอดภัยสูงสุดใน JavaScriptเป็น9007199254740991ซึ่งเป็น 16 หลักยาว ใน ES7 สามารถคำนวณได้ด้วย 7 ไบต์ต่อไปนี้:

2**53-1

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

Math.pow(2,53)-1

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


2

ใช้เศษส่วนในสถานที่ของการลอย

ตัวอย่าง: 1./3แทนที่0.333333333

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