จำนวน Endian น้อยไปเป็นการแปลงสตริง


13

บทนำ

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

let liEnd= num => num.toString(16).padStart(8,'0').match(/../g).reverse().join``;
console.log(liEnd(304767)) // 304767 dec = 0x4a67f hex

ท้าทาย

ฟังก์ชั่นการเขียนซึ่งจะใช้จำนวนเต็ม 32 บิตที่ไม่ได้ลงชื่อในการป้อนข้อมูลและผลิตสตริงเลขฐานสิบหก 8 หลักที่มีคำสั่ง endian น้อย อัลกอริทึมตัวอย่างซึ่งทำงาน:

  • แปลงชาไปเป็นสตริงฐานสิบหกเช่น: 304767 -> '4a67f'
  • เพิ่มศูนย์ padding เพื่อรับสาย 8-char: '0004a67f'
  • แยกสตริงเป็นสองชิ้น 2 ถ่าน: '00','04','a6','7f'
  • กลับคำสั่งของชิ้น '7f','a6','04','00'
  • เข้าร่วมชิ้นและกลับมาเป็นผล: '7fa60400'

ตัวอย่างอินพุตและเอาต์พุต

หมายเลขอินพุต (หรือสตริงที่มีหมายเลข dec) อยู่ทางด้านซ้ายของ->สตริง hex เอาต์พุตอยู่ทางด้านขวา

2141586432 -> 0004a67f
304767     -> 7fa60400

คำตอบ:



6

Python 3 , 37 ไบต์

lambda n:n.to_bytes(4,"little").hex()

ลองออนไลน์!

โซลูชันแบบเรียกซ้ำโดยใช้เลขคณิต ( 50 49 ไบต์ใช้งานได้กับPython 2 ) :

f=lambda n,i=4:i*'1'and"%02x"%(n%256)+f(n>>8,i-1)

ลองออนไลน์!

-1 ไบต์ขอบคุณ @JonathanAllan


ฉันจะบอกว่าส่ง recursive หนึ่งเป็นรายการ Python 2 :)
Jonathan Jonathan Allan

f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)บันทึกไบต์ :)
Jonathan Allan

@JanathanAllan ขอบคุณ ฉันไม่คุ้นเคยกับเคล็ดลับ Python 2 ทั้งหมดและไม่เห็นว่ามันจะสั้นลงได้อย่างไร
Joel

มันไม่ได้ แต่ 37 จะไม่ทำงานใน py 2
Jonathan Allan

ใช่. บิวด์อินบางตัวเป็น Python-3-only
Joel

6

R , 54 53 ไบต์

format.hexmode(scan()%/%256^(0:3)%%256%*%256^(3:0),8)

ลองออนไลน์!

แต่ละกลุ่มของตัวละคร 2 ตัวนั้นจริง ๆ แล้วเป็นตัวแทนเลขฐานสิบหกของตัวเลขในฐาน 256 scan()%/%256^(0:3)%%256แปลงเป็นตัวเลขฐาน 256 โดยมีตัวเลข 4 หลักกลับรายการ ...%*%256^(3:0)รวมเป็นจำนวนเต็มเดียวและformat.hexmode(...,8)แปลงตัวเลขนั้นให้เป็นเลขฐานสิบหกที่มี 8 หลัก


5

JavaScript (ES7),  59  57 ไบต์

การจัดการสตริง

n=>(n+2**32).toString(16).match(/\B../g).reverse().join``

ลองออนไลน์!

อย่างไร?

เราทำการแปลงn+232เป็นเลขฐานสิบหกเพื่อให้แน่ใจว่ามีการนำ0ของทั้งหมด:

(304767 + 2**32).toString(16) // --> '10004a67f'

ลองออนไลน์!

เราใช้การแสดงออกปกติ/\B../gเพื่อจับคู่ทุกกลุ่มของตัวเลข 2 หลักโดยไม่สนใจ1นำหน้าด้วย\B( ขอบเขตที่ไม่ใช่คำ )

'10004a67f'.match(/\B../g) // --> [ '00', '04', 'a6', '7f' ]

ลองออนไลน์!

เราreverse()และjoin()เพื่อให้ได้สตริงสุดท้าย


JavaScript (ES6), 61 ไบต์

ฟังก์ชั่นวนซ้ำ

f=(n,k=4)=>k?[(x=n&255)>>4&&'']+x.toString(16)+f(n>>8,k-1):''

ลองออนไลน์!


⭐ - คุณได้รับดาวสำหรับคำตอบที่ดี - ฉันชอบมันสั้น ๆ แต่ก็ยังสะอาดและ "มนุษย์เปลี่ยนได้" :)
Kamil Kiełczewski


5

C # (Visual C # Interactive Compiler) , 54 ไบต์

x=>$"{(x=x>>16|x<<16)>>8&16711935|(x&16711935)<<8:x8}"

บันทึกแล้ว 4 ไบต์ขอบคุณ @PeterCordes

ลองออนไลน์!

คำอธิบาย

x=>                                                    //Lambda taking in an uint
     (x=x>>16|x<<16)                                   //Swap the first two and the last two bytes of the uint (0x7fa60400 -> 0x04007fa6)
                    >>8&16711935|(x&16711935)<<8       //Swap each pair of bytes in every group of 2 bytes (0x04007fa6 -> 0x0004a67f)
  $"{                                           :x8}"  //Format as hex string, padded with leading zeroes to length 8

คุณสามารถลดขนาด4278255360หน้ากากให้คงที่16711935( 0xff00ff) ถ้าคุณเปลี่ยนก่อนที่จะปิดบังได้หรือไม่? หรือว่ามีค่าใช้จ่ายพิเศษ parens นอกจากนี้ถ้าไม่เช่นนั้น0xff00ff00ความยาวเท่ากัน แต่มีความหมายกับมนุษย์มากขึ้น
Peter Cordes

@PeterCordes นอกจากนี้ยังมีข้อได้เปรียบเพิ่มเติมของความสามารถในการลบวงเล็บที่>>มีความสำคัญสูงกว่า&ซึ่งได้บันทึก 4 ไบต์รวม ขอบคุณ!
ศูนย์รวมแห่งความไม่รู้

เย็น. ในส่วน "คำอธิบาย" ของคุณฉันขอแนะนำให้เขียนค่าคงที่เป็นเลขฐานสิบหก
Peter Cordes

4

Japt -P , 10 ไบต์

sG ùT8 ò w

ลองมัน

sG ùT8 ò w     :Implicit input of integer
s              :Convert to string
 G             :  In base-16
   ù           :Left pad
    T          :  With 0
     8         :  To length 8
       ò       :Split into 2s
         w     :Reverse
               :Implicitly join and output

อะไร-Pทำอย่างไร
SS Anne

answer คำตอบของคุณอยู่ในอันดับต้น ๆ (คุณสามารถเพิ่มคำอธิบายได้ไหม)
Kamil Kiełczewski

@ JL2210 จากเอกสาร : " -P: หากผลลัพธ์เป็นอาร์เรย์ผลลัพธ์ที่ไม่มีตัวคั่น (เช่นเชื่อมกับP) " ดังนั้นการตั้งค่าสถานะสำหรับการเป็นนัยแทนที่จะเข้าร่วมอย่างชัดเจนเพื่อบันทึกไบต์ :)
Kevin Cruijssen

2
@ KamilKiełczewskiเพิ่มคำอธิบาย
Shaggy


4

Python 2 , 43 ไบต์

lambda n:[("%08x"%n)[i^6]for i in range(8)]

ลองออนไลน์!

-4 ไบต์ขอบคุณbenrg

เอาต์พุตรายการอักขระ 6, 7, 4, 5, 2, 3, 0, 1คำนวณโดยการเรียกในการสั่งซื้อเลขฐานสิบหกของการป้อนข้อมูลที่ดัชนี


2
[i^6]for i in range(8)บันทึกไม่กี่ไบต์
benrg

อนุญาตให้ส่งออกรายการแทนที่จะเป็นสตริงหรือไม่
Qwertiy

ผลลัพธ์เนื่องจากรายการไม่เหมาะสำหรับวิญญาณของคำถาม imo
qwr

3

C (gcc)ผู้ไม่เชื่อเรื่องพระเจ้า endian, ไม่มี libs มาตรฐาน, 92 91 ไบต์

h(n)เป็นฟังก์ชันเลขจำนวนเต็มฐานสิบหกหลักเดียว
f(x,p)ใช้จำนวนเต็มและchar[8]ตัวชี้ ผลลัพธ์คือ 8 ไบต์ของcharข้อมูล ( ไม่สิ้นสุด 0 ยกเว้นว่าผู้โทรทำเช่นนั้น)

สมมติฐาน: ชุดอักขระ ASCII ส่วนประกอบที่สมบูรณ์ของ 2 intดังนั้นการเปลี่ยนที่ถูกต้องในที่สุดจะทำให้บิตเครื่องหมายลงและการแปลง a uint32_tเพื่อintไม่ทำให้เกิดรูปแบบบิตหากตั้งค่าบิตสูงไว้ intอย่างน้อย 32- บิต (กว้างกว่าอาจปล่อยให้มันทำงานบนการใช้งานส่วนเสริมหรือเครื่องหมาย C ขนาด 1)

Non-สมมติฐาน: อะไรเกี่ยวกับการดำเนินการสั่งไบต์หรือ signedness charของ

i;h(n){n&=15;return n>9?n+87:n+48;}f(x,p)char*p;{for(i=5;--i;x>>=8)*p++=h(x>>4),*p++=h(x);}

ลองออนไลน์! รวมถึงผู้โทรทดสอบที่ใช้printf("%.8s\n", buf)พิมพ์บัฟเฟอร์เอาต์พุตโดยไม่ต้องจบการทำงาน 0

Ungolfed:

int h(n){n&=15;return n>9 ? n+'a'-10 : n+'0';}      // single digit integer -> hex

int i;
void ungolfed_f(x,p)char*p;{
    for(i=5; --i; x>>=8)   // LS byte first across bytes
        *p++=h(x>>4),      // MS nibble first within bytes
        *p++=h(x);
}

การทำn&=15;ข้างในh(x)เป็นแบบคุ้มทุน 6 ไบต์เทียบกับ 3 แต่ละอัน&15เพื่อแยกตอดต่ำที่ไซต์การโทรทั้งสอง

,เป็นจุดลำดับ (หรือเทียบเท่าในคำศัพท์ที่ทันสมัย) ดังนั้นจึงปลอดภัยที่จะทำ*p++= stuffสองครั้งในหนึ่งคำสั่งเมื่อคั่นด้วย,โอเปอเรเตอร์

>>ในจำนวนเต็มที่ลงนามจะถูกกำหนดให้ดำเนินการเป็นเลขคณิตหรือตรรกะ GNU C นิยามว่าเป็นส่วนประกอบของเลขคณิต 2 แต่ในเครื่องเสริมของ 2 มันไม่สำคัญเพราะเราไม่เคยดู 0 หรือสำเนาบิตของ shift-in ในที่สุด MSB ดั้งเดิมจะลงไปสู่ไบต์ต่ำที่ไม่เปลี่ยนแปลง นี่ไม่ใช่กรณีของเครื่องหมาย / ขนาดและฉันไม่แน่ใจเกี่ยวกับส่วนประกอบ 1 ของ

ดังนั้นนี่อาจเป็นแบบพกพาสำหรับการใช้งาน C เท่านั้น (หรือที่intเป็นที่กว้างขึ้นกว่า 32 บิตดังนั้นบิต 31 เป็นเพียงส่วนหนึ่งของขนาด.) ได้ลงนาม -> ลงนามแปลงยัง munges บิตรูปแบบสำหรับจำนวนเต็มลบดังนั้น&15บนintเท่านั้นที่จะดึงแทะของมูลค่าไม่ได้ลงนามเดิมในวันที่ 2 ของการเติมเต็ม อีกครั้งเว้นแต่intเป็นวงกว้างกว่า 32 บิตดังนั้นปัจจัยการผลิตทั้งหมดจะไม่เป็นลบ

รุ่น golfed มี UB จากการล้มปิดท้ายฟังก์ชั่นที่ไม่เป็นโมฆะ ที่จะไม่คืนค่าเพียงเพื่อหลีกเลี่ยงประกาศแทนการเริ่มต้นvoid intคอมไพเลอร์สมัยใหม่จะหยุดสิ่งนี้เมื่อเปิดใช้การเพิ่มประสิทธิภาพ


แรงจูงใจ: ฉันกำลังพิจารณาคำตอบ asm x86 หรือ ARM Thumb คิดว่ามันอาจสนุกที่จะทำมันด้วยตัวเองใน C บางทีสำหรับ asm ที่สร้างโดยคอมไพเลอร์เป็นจุดเริ่มต้น ดู/programming/53823756/how-to-convert-a-number-to-hexสำหรับ x86 asm ที่มีประสิทธิภาพด้านความเร็วรวมถึงรุ่น AVX512VBMI ที่มีเพียง 2 คำสั่ง (แต่ต้องการควบคุมเวกเตอร์สำหรับ vpmultishiftqb และ vpshufb ดังนั้นจะไม่ดีสำหรับการเล่นกอล์ฟ) โดยปกติจะใช้งานพิเศษสำหรับ SIMD เพื่อ byte-reverse ลงในคำสั่งการพิมพ์ใน x86 แบบ endian ดังนั้นการส่งออก hex แบบกลับด้านแบบไบต์จึงทำได้ง่ายกว่าปกติ


ความคิดอื่น ๆ

ฉันถือว่าการใช้จำนวนเต็มโดยการอ้างอิงและวนลูปผ่านไบต์ด้วยchar*ในการใช้งาน C-endian เล็ก ๆ น้อย ๆ (เช่น x86 หรือ ARM) แต่ฉันไม่คิดว่าจะช่วยได้มากนัก

ใช้sprintfในการทำครั้งละ 1 ไบต์, 64 ไบต์หลังจากเล่นกอล์ฟ:

int i;
void f(x,p)char*p;{
        for(i=4;sprintf(p,"%.2x",x&255),--i;x>>=8)
                p+=2;
}

แต่ถ้าเราใช้ printf เหมือนฟังก์ชั่นที่เราอาจรวมทั้งไบต์-swap และทำ%xprintf ของสิ่งที่ทั้งเหมือน@ คำตอบของ


⭐ - คุณได้รับดาวสำหรับคำตอบที่ดี
Kamil Kiełczewski

3

x86 รหัสเครื่อง SIMD (AVX512-VBMI), 36 ไบต์

(16 ไบต์ซึ่งเป็นตารางการค้นหาฐานสิบหก)

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

จาก C, เรียกว่าเป็น__m128i retval = lehex(_mm_cvtsi32_si128(x))กับ x86-64 ประชุมโทร System V หรือ MS vectorcallWindows

# disassembly with machine-code bytes (the answer) and NASM source code.
0000000000401000 <lehex>:
  401000:       c5 f1 72 d0 04          vpsrld      xmm1, xmm0, 4         ; AVX1
  401005:       c5 f1 60 c8             vpunpcklbw  xmm1, xmm1, xmm0      ; AVX1
  401009:    62 f2 75 08 8d 05 01 00 00 00 vpermb  xmm0, xmm1, [rel .hex_lut]
  401013:       c3                      ret    

0000000000401014 <lehex.hex_lut>:
  401014:     30 31 ...  61 62 ...     .hex_lut:  db "0123456789abcdef"

รวม = 0x24 = 36 ไบต์

ดูวิธีแปลงตัวเลขเป็นฐานสิบหก? บน SO สำหรับวิธีการทำงาน (SSE2 สำหรับ shift / punpck จากนั้นvpermbบันทึกงานที่เราต้องการpshufbAVX1 แทน SSE2 / SSSE3 ยังหลีกเลี่ยงmovapsสำเนาการลงทะเบียนด้วย)

โปรดสังเกตว่าpunpcklbwด้วยโอเปอเรเตอร์ต้นทางในลำดับนั้นจะทำให้เราตอดสำคัญที่สุดของไบต์อินพุตต่ำในองค์ประกอบไบต์ต่ำสุดจากนั้นจึงตอดสำคัญน้อยที่สุดของไบต์ต้นทางต่ำสุด (ในคำตอบ SO นั้น a bswapถูกใช้ในอินพุตเพื่อให้ได้ผลลัพธ์ตามลำดับการพิมพ์มาตรฐานด้วย SSE2 เท่านั้น แต่ที่นี่เราต้องการคำสั่ง: แทะสูงในองค์ประกอบที่ต่ำกว่าภายในแต่ละไบต์ แต่ยังคงลำดับไบต์น้อยสุด)

ถ้าเรามีค่าคงที่ข้อมูลที่มากขึ้นเราสามารถบันทึกที่อยู่โหมดพื้นที่โดยการทำอย่างใดอย่างหนึ่งmov edx, imm32แล้วใช้[rdx+16]หรืออะไรก็ตามที่อยู่ในโหมด vpbroadcastb xmm0, [rdx+1]หรือ

แต่ฉันคิดว่า hex LUT + ขนาด 16 ไบต์vpermbยังคงดีกว่าการใช้n>9 : n+'a'-10 : n+'0'เงื่อนไข: ซึ่งต้องใช้ค่าคงที่ 3 ค่าและอย่างน้อย 3 คำแนะนำกับ AVX512BW byte-masking (เปรียบเทียบกับ mask vpaddb, merge-masked vpaddb) หรือมากกว่าด้วย AVX1 หรือ SSE2 (ดูวิธีแปลงตัวเลขเป็นฐานสิบหก?บน SO สำหรับรุ่น SSE2 ของรุ่นนั้น) และคำสั่ง AVX512BW แต่ละคำสั่งจะมีความยาวอย่างน้อย 6 ไบต์ (4-byte EVEX + opcode + modrm) อีกต่อไปด้วยการแทนที่ในโหมดการกำหนดแอดเดรส

ที่จริงแล้วมันจะใช้เวลาอย่างน้อย4คำแนะนำเพราะเราจำเป็นต้องล้างขยะสูงด้วยandps(หรือ EVEX vpanddด้วยตัวถูกดำเนินการหน่วยความจำออกอากาศ 4 ไบต์) ก่อนการเปรียบเทียบ และแต่ละอันต้องการค่าคงที่แบบเวกเตอร์ที่ต่างกัน AVX512 มีตัวถูกดำเนินการหน่วยความจำออกอากาศ แต่สำหรับองค์ประกอบที่ 32 บิตและกว้างกว่าเท่านั้น เช่นEveXvpaddb 's ถูกดำเนินการที่ผ่านมาเป็นเพียงไม่xmm3/m128 xmm3/m128/m8bcst(พอร์ตโหลดของ Intel สามารถออกอากาศแบบ 32 และ 64 บิตได้ฟรีโดยเป็นส่วนหนึ่งของ load uop ดังนั้น Intel จึงออกแบบ AVX512BW เพื่อสะท้อนและไม่สามารถเข้ารหัสไบต์หรือตัวถูกดำเนินการหน่วยความจำคำแทนได้ ทำการออกอากาศ dword เพื่อให้คุณยังคงสามารถบีบอัดค่าคงที่ของคุณถึง 4 ไบต์: /.)

เหตุผลที่ฉันใช้AVX512VBMIvpermbแทน SSSE3 / AVX1 pshufbนั้นเป็นสองเท่า:

  • vpermbละเว้นบิตสูงของตัวเลือก (v)pshufbศูนย์ไบต์ตามบิตของเวกเตอร์ควบคุมสูงและจำเป็นต้องมีส่วนเสริมpandหรือandpsแยกส่วนที่เป็นจริง ด้วยขนาด XMM / 16 ไบต์vpermbเท่านั้นมีลักษณะที่ต่ำ 4 บิตขององค์ประกอบสับเปลี่ยนการควบคุมเช่นบิต[3:0]ในสัญกรณ์ของอินเทลในส่วนการดำเนินงาน
  • vpermbสามารถนำข้อมูลที่จะสับ (ตารางการค้นหา) เป็นตัวถูกดำเนินการหน่วยความจำ (v)pshufbตัวถูกดำเนินการ xmm / mem เป็นเวกเตอร์ควบคุมการสลับ

โปรดทราบว่า AVX512VBMI นั้นมีเฉพาะใน CannonLake / Ice Lake เท่านั้นดังนั้นคุณอาจต้องใช้เครื่องจำลองเพื่อทดสอบสิ่งนี้เช่น SDE ของ Intel


⭐ - คุณได้รับดาวสำหรับคำตอบที่ดี
Kamil Kiełczewski

@ KamilKiełczewski: ขอบคุณมาก การแปลงตัวเลขเป็นฐานสิบหกอย่างมีประสิทธิภาพเป็นหนึ่งในสิ่งที่ฉันโปรดปราน มันเป็นกรณีการใช้งานที่ดีสำหรับเทคนิคที่ประณีตและการจัดการบิต
Peter Cordes

3

Scala , 58 40 36 ไบต์

"%08X"format Integer.reverseBytes(_)

ลองออนไลน์!

ยังคงใช้ builtin เพื่อย้อนกลับจำนวนไบต์ของIntแต่ใช้formatในการจัดรูปแบบIntเป็น Hex toHexStringไม่จำเป็นต้องโทร

ถอด parens on formatออก _ตอนนี้หมายความว่าอาร์กิวเมนต์สามารถนำมาใช้โดยปริยาย


2

มา (gforth) , 52 51 40 ไบต์

: f hex 0 4. do <# # # 0. #> type loop ;

ลองออนไลน์!

คำอธิบายรหัส

: f           \ start a new word definition
  hex         \ set the current base to base 16
  0           \ convert the input number to a double-cell integer
  4. do       \ start a counted loop from 0 to 3
    <# # #    \ start a formatted numeric string and move last 2 digits to format area
    0.        \ move remaining digits down the stack
    #>        \ delete top two stack value and convert format area to string
    type      \ output string
  loop        \ end loop
;             \ end word definition




2

K4 , 12 11 ไบต์

วิธีการแก้:

,/$|4_0x0\:

ตัวอย่าง:

q)k),/$|4_0x0\:304767
"7fa60400"
q)0W
"0004a67f"

คำอธิบาย:

ค่อนข้างตรงกับคำถามที่ถาม:

,/$|4_0x0\: / the solution
      0x0\: / split to bytes
    4_      / drop first 4 bytes
   |        / reverse
  $         / convert to string
,/          / flatten

หมายเหตุ:

  • -1 ไบต์เป็นตัวเลข K4 มีความยาว (64 บิต) โดยค่าเริ่มต้นดังนั้นการลดลง 4 ไบต์ (32 บิต)

answer คำตอบของคุณอยู่ในอันดับต้น ๆ
Kamil Kiełczewski

2

PHP , 31 ไบต์

<?=unpack(H8,pack(V,$argn))[1];

ลองออนไลน์!

ใช้ประโยชน์จากชุดของ PHP และแกะออกฉันจะแพ็คอินพุทที่ไม่ได้ลงนามด้วยรูปแบบ "32 บิตของ endian byte order" ( V) ลงในไบนารี่สตริงแล้วแกะมันHออกมาด้วย

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


PHP pack()/ unpack()ฟังก์ชั่นยอดเยี่ยมสำหรับ 0 เท่าที่คุณต้องการในโครงการ PHP ส่วนใหญ่ ยินดีด้วยคุณพบการใช้งานแล้ว!
640KB

1

ถ่าน 11 ไบต์

⪫⮌⪪﹪%08xN²ω

ลองออนไลน์! การเชื่อมโยงคือการใช้รหัสเวอร์ชันอย่างละเอียด คำอธิบาย:

        N   Input as a number
   ﹪%08x    Format using literal string
  ⪪      ²  Split into pairs of characters
 ⮌          Reverse
⪫         ω Join
            Implicitly print

19 ไบต์โดยไม่ต้องใช้รูปแบบ Python:

⪫…⮌⪪⍘⁺X²¦³⁶N¹⁶¦²¦⁴ω

ลองออนไลน์! การเชื่อมโยงคือการใช้รหัสเวอร์ชันอย่างละเอียด คำอธิบาย:

           N        Input as a number
     ⁺              Plus
       ²            Literal 2
      X             To power
         ³⁶         Literal 36
    ⍘               Convert to base
            ¹⁶      Literal 16
   ⪪           ²    Split into pairs of digits
  ⮌                 Reverse the list
 …               ⁴  Take the first 4 pairs
⪫                 ω Join together
                    Implicitly print

answer คำตอบของคุณอยู่ในอันดับต้น ๆ
Kamil Kiełczewski


1

J , 10 ไบต์

8{._1{3!:3

ลองออนไลน์!

อย่างไร

3!:3เป็นเจ "ร่วมต่างชาติ" สำหรับการแสดง hex, เอกสารที่นี่ นั่นคือมันเป็น builtin สำหรับการแปลงเป็น hex อย่างไรก็ตามมันออกมันไม่ได้สิ่งที่เราต้องการ เช่นทำงาน:

3!:3 (304767)

ผลิต:

e300000000000000
0400000000000000
0100000000000000
0000000000000000
7fa6040000000000

ความหมายของบรรทัดอื่น ๆ อธิบายไว้ในหน้าเอกสารที่ฉันเชื่อมโยงไปด้านบน ไม่ว่าในกรณีใดมันชัดเจนว่าเราต้องการ 8 ตัวอักษรแรกของบรรทัดสุดท้าย

_1{ รับบรรทัดสุดท้าย

8{. รับ 8 ตัวแรกของมัน


answer คำตอบของคุณอยู่ในอันดับต้น ๆ
Kamil Kiełczewski

1

Ruby , 31 27 ไบต์

จบลงด้วยการเป็นพอร์ตของคำตอบ PHP ของ Night2เพราะ Ruby มีฟังก์ชั่น pack / unpack เดียวกัน

->*i{i.pack(?V).unpack'H8'}

ลองออนไลน์!

คำตอบขนาด 31 ไบต์เดิมของฉันที่ไม่ได้ใช้ประโยชน์จากโหมดคลายแพ็กเกจ H8 เนื่องจากฉันไม่รู้:

->*i{'%02x'*4%i.pack(?V).bytes}

ลองออนไลน์!


1

Windows Batch ขนาด 90 ไบต์

@for /l %%x in (24,-8,0)do @set/aa=%1^>^>%%x^&255&cmd/cexit !a!&<nul set/p=!=exitcode:~-2!

เรียกใช้บรรทัดคำสั่งด้วย / v เพื่อเปิดใช้งานการขยายล่าช้า


1

x86 รหัสเครื่อง 32 บิต 24 21 ไบต์

การเปลี่ยนแปลง: -3 ไบต์: แทนที่มาตรฐานเพิ่ม / cmp / jbe / เพิ่มด้วยแฮ็ค DAS โดย @peter ferrie

64 บิต: ยังคง 24 ไบต์ โหมดยาวจะลบ DAS opcode
โหมด 16 บิต: ขนาดตัวถูกดำเนินการเริ่มต้นคือ 16 บิต แต่สเป็คปัญหาคือ 32- บิตโดยกำเนิด รวมถึงรหัสเลขฐานสิบหก 8 หลักแบบตายตัว


Byte-reverse พร้อมด้วยbswapmanual int-> hex ในลำดับมาตรฐาน (ที่สำคัญที่สุดคือตอดแรกเขียนเลขฐานสิบหกไปยังบัฟเฟอร์เอาต์พุตถ่านตามลำดับจากน้อยไปหามาก) วิธีนี้หลีกเลี่ยงการเปิดการวนซ้ำเพื่อสลับลำดับระหว่าง nibbles ภายใน byte vs. ข้ามไบต์

callable void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);เหมือน x86-64 System V ยกเว้นว่าใช้งานไม่ได้ในโหมด 64 บิต (ต้องการตัวชี้เอาต์พุตใน EDI สำหรับstosbหมายเลขอินพุตสามารถอยู่ในรีจิสเตอร์อื่นที่ไม่ใช่ ECX หรือ EAX)

     1                             lehex:
     2 00000000 0FCE                   bswap  esi
     3 00000002 6A08                   push   8            ; 8 hex digits
     4 00000004 59                     pop    ecx
     5                             .loop:                ;do{
     6 00000005 C1C604                 rol    esi, 4       ; rotate high nibble to the bottom
     7                             
     8 00000008 89F0                   mov    eax, esi
     9 0000000A 240F                   and    al, 0x0f     ; isolate low nibble
    10 0000000C 3C0A                   cmp al, 10          ; set CF according to digit <= 9
    11 0000000E 1C69                   sbb al, 0x69        ; read CF, set CF and conditionally set AF
    12 00000010 2F                     das                 ; magic, which happens to work
    13                             
    14 00000011 AA                     stosb               ; *edi++ = al
    15 00000012 E2F1                   loop  .loop       ; }while(--ecx)
    16                             
    17 00000014 C3                     ret

ขนาด = 0x15 = 21 ไบต์

กรณีทดสอบ T86 FASM 32 บิต x86พร้อมด้วยตัวเรียก asm ที่ใช้writeเรียกของระบบเพื่อเขียนเอาต์พุตหลังจากเรียกสองครั้งเพื่อผนวก 2 สตริงลงในบัฟเฟอร์ ทดสอบเลขฐานสิบหกทั้งหมด 0..F รวมถึง 9 และ A ที่ขอบเขตระหว่างตัวเลขกับตัวอักษร

DASสับ - x86 มีธงครึ่งพกพาสำหรับการดำเนินการของตอดต่ำ มีประโยชน์สำหรับการบรรจุแบบ BCD เช่นคำสั่ง DAS สำหรับใช้หลังจากลบจำนวนเต็ม BCD 2 หลักสองตัว ด้วยแทะเล็มต่ำของ AL ที่อยู่นอกช่วง 0-9 เราจึงดูถูกเหยียดหยามที่นี่อย่างแน่นอน

แจ้งให้ทราบif (old_AL > 99H) or (old_CF = 1)แล้ว AL ← AL − 60H;ส่วนหนึ่งของส่วนการดำเนินงานในคู่มือ; SBB เสมอชุด CF ที่นี่เพื่อให้เป็นส่วนหนึ่งที่เกิดขึ้นเสมอ นั่นและช่วง ASCII สำหรับตัวอักษรตัวพิมพ์ใหญ่เป็นสิ่งที่กระตุ้นให้เลือกsub al, 0x69

  • cmp 0xD, 0xA ไม่ได้ตั้งค่า CF
  • sbb 0xD - 0x69wraps ไปที่ AL =0xA4เป็นอินพุตไปยัง DAS (และตั้งค่า CF ล้างค่า AF)
  • no AL - = 6 ในส่วนแรกของ DAS (เนื่องจาก 4> 9 เป็นเท็จและ AF = 0)
  • AL - = 0x60 ในส่วนที่สองปล่อย0x44ให้เป็นรหัส ASCII สำหรับ'D'

เทียบกับตัวเลข:

  • cmp 0x3, 0xA ชุด CF
  • sbb 3 - 0x69 - 1= AL = 0x99 และตั้งค่า CF และ AF
  • no AL - = 6 ในส่วนแรกของ DAS (9> 9 เป็นเท็จ แต่มีการตั้งค่า AF) โดยปล่อย 0x93
  • AL - = 0x60 ในส่วนที่สองออกจาก 0x33 รหัส ASCII '3'สำหรับ

การลบ0x6aใน SBB จะตั้งค่า AF สำหรับทุกหลัก <= 9 ดังนั้นตัวเลขทั้งหมดจะเป็นไปตามตรรกะเดียวกัน และปล่อยให้มันถูกลบออกสำหรับเลขฐานสิบหกทุกตัวอักษร เช่นการใช้ประโยชน์จากการจัดการ DAS แบบแยกย่อย 9 / A อย่างถูกต้อง


โดยปกติ (สำหรับประสิทธิภาพ) คุณจะต้องใช้ตารางการค้นหาสำหรับการวนซ้ำแบบสเกลาร์หรืออาจเป็น 2x แบบไม่มีสาขาleaและการcmp/cmovเพิ่มแบบมีเงื่อนไข แต่al, imm8คำแนะนำขนาด2 ไบต์ถือว่าเป็นเรื่องใหญ่สำหรับรหัสขนาด


x86-64 เวอร์ชั่น : เพียงแค่ส่วนหนึ่งที่แตกต่างกันระหว่างและand al, 0xfstosb

;; x86-64 int -> hex  in 8 bytes
    10 0000000C 0430                   add    al, '0'
    11 0000000E 3C39                   cmp    al, '9'
    12 00000010 7602                   jbe  .digit
    13 00000012 0427                     add    al, 'a'-10 - '0'     ; al =  al>9 ? al+'a'-10 : al+'0'
    14                             .digit:

สังเกตว่าadd al, '0' มักจะทำงานและเงื่อนไขเพิ่มเพียง แต่เพิ่มความแตกต่างระหว่าง'a'-10และ'0'จะทำให้มันเป็นเพียงแค่ifแทน/ifelse

ทดสอบและการทำงานโดยใช้เดียวกันmainโทรเป็นคำตอบของฉัน Cซึ่งการใช้งานและchar buf[8]printf("%.8s\n", buf)


คุณสามารถสร้างเกร็ดเล็กเกร็ดน้อยออนไลน์ที่ทำงานในเช่นที่นี่ ?
Kamil Kiełczewski

@ KamilKiełczewski: TIO ทำให้เป็นไปไม่ได้ (AFAIK) ในการเขียนผู้โทรเข้าใน C เพื่อทดสอบฟังก์ชั่น asm ดังนั้นฉันมักจะไม่รำคาญ แต่ก็แน่ใจว่าเมื่อคุณถามและsys_writeสามารถส่งออกสายความยาวคงที่ได้อย่างง่ายดาย โอ้น่าสนใจผมไม่ได้ตระหนัก FASM ใน TIO ช่วยให้คุณสร้าง executables 32 บิตแตกต่างกับ NASM -felf32ที่มันไม่เคารพ ฉันชอบ x86-64 อยู่แล้วและคำตอบนี้ไม่ได้บันทึกไบต์ใด ๆ จากรหัส 32 บิต
Peter Cordes

⭐ - คุณได้รับดาวสำหรับคำตอบที่ดี
Kamil Kiełczewski

1
@ JL2210: คุณหมายถึงsprintfอะไร ฉันไม่คิดว่า libc มีฟังก์ชั่น int-> string ที่มีประโยชน์นอกเหนือจากฟังก์ชั่นสตริงตามรูปแบบเฉพาะ string-> int เช่น strtoul แต่ใช่ bswap / printf น่าจะสั้นกว่านี้หากคุณสามารถหาวิธีนับจำนวนไบต์สำหรับรายการ GOT สำหรับฟังก์ชั่นในไลบรารีแบบไดนามิก (นอกเหนือจากcall [rel printf wrt ..got]ไซต์การโทร6 ไบต์) executables ที่เชื่อมโยงแบบสแตติกขั้นต่ำสามารถมีขนาดเล็กกว่าไดนามิกอย่างน้อยเมื่อสร้างldด้วยค่าเริ่มต้นปกติ แต่ฉันไม่คิดว่ามันจะสมเหตุสมผลที่จะเชื่อมโยงมันแบบคงที่ แต่ไม่นับขนาดรหัส
Peter Cordes

1
@ JL2210: จำไว้ว่านี่เป็นคำตอบของรหัสเครื่อง x86 ไม่ใช่ขนาดข้อความ asm ฉันไม่ได้ใช้ฟังก์ชั่น libc ในการตอบกลับรหัสเครื่องก่อนหน้านี้มีเพียงการเรียกใช้ระบบ Linux (เช่นใน Fibonacci) และ IDK ว่าจะนับค่าใช้จ่ายอย่างไรหรือว่าฉันต้องการเขียนคำตอบเครื่องด้วยรหัส libc หรือไม่ . มีกรณีใช้งานสำหรับรหัสเครื่อง x86 ที่ libc ไม่พร้อมใช้งานเช่นใน bootloader
Peter Cordes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.