pengantar
Selama bekerja dengan generator BMP (bitmap) saya menghadapi masalah dalam mengubah angka menjadi sedikit string hex endian. Berikut adalah fungsi yang saya buat dalam JavaScript - tetapi bertanya-tanya bagaimana kode kecil dapat bekerja dengan cara yang sama
let liEnd= num => num.toString(16).padStart(8,'0').match(/../g).reverse().join``;
console.log(liEnd(304767)) // 304767 dec = 0x4a67f hex
Tantangan
Tulis fungsi yang akan mengambil nomor integer 32bit tanpa tanda pada input, dan menghasilkan 8-digit string heksadesimal dengan sedikit urutan endian. Contoh algoritma yang melakukan pekerjaan:
- konversi numb ke hex string misalnya:
304767 -> '4a67f'
- tambahkan padding nol untuk mendapatkan string 8-char:
'0004a67f'
- pisahkan string menjadi empat bagian 2-char:
'00','04','a6','7f'
- urutan terbalik
'7f','a6','04','00'
- bergabunglah dan kembalikan sebagai hasilnya:
'7fa60400'
Contoh Input dan Output
Nomor input (atau string dengan angka dec) ada di sebelah kiri ->
, string hex output ada di sebelah kanan
2141586432 -> 0004a67f
304767 -> 7fa60400
f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)
menghemat satu byte :)R ,
5453 byteCobalah online!
Setiap kelompok 2 karakter sebenarnya adalah representasi heksa dari digit dalam basis 256.
scan()%/%256^(0:3)%%256
mengkonversi ke nomor 256 basis dengan 4 digit terbalik,...%*%256^(3:0)
bergabung dengan mereka sebagai integer tunggal, danformat.hexmode(...,8)
mengkonversi angka itu ke representasi hex dengan 8 digit.sumber
JavaScript (ES7),
5957 byteManipulasi string.
Cobalah online!
Bagaimana?
Kami pertama-tama mengonversi ke heksadesimal untuk memastikan bahwa semua terdepan disertakan:n + 232 0
Cobalah online!
Kami menggunakan persamaan reguler1
/\B../g
untuk mencocokkan semua grup yang terdiri dari 2 digit, mengabaikan terimakasih atas ( batas non- kata ).\B
Cobalah online!
Kami
reverse()
danjoin()
untuk mendapatkan string terakhir.JavaScript (ES6), 61 byte
Fungsi rekursif.
Cobalah online!
sumber
Zsh , 46 byte
Cobalah online!
sumber
C # (Visual C # Interactive Compiler) , 54 byte
Disimpan 4 byte berkat @PeterCordes
Cobalah online!
Penjelasan
sumber
4278255360
konstanta topeng ke16711935
(0xff00ff
) jika Anda menggeser sebelum menutup? Atau apakah itu memerlukan tambahan paren? Juga, jika tidak maka0xff00ff00
panjangnya sama tetapi jauh lebih bermakna bagi manusia.>>
memiliki prioritas lebih tinggi daripada&
, yang disimpan total 4 byte. Terima kasih!Japt
-P
, 10 byteCobalah
sumber
-P
harus dilakukan-P
: Jika output adalah sebuah array, output tanpa pemisah (yaitu bergabung denganP
). ". Jadi flag adalah untuk implisit, bukan gabungan eksplisit untuk menyimpan byte. :)C (gcc) , 30 byte
Cobalah online!
sumber
Python 2 , 43 byte
Cobalah online!
-4 byte terima kasih kepada benrg
Mengeluarkan daftar karakter. Dihitung dengan mengambil, secara berurutan, digit hex input pada indeks
6, 7, 4, 5, 2, 3, 0, 1
.sumber
[i^6]for i in range(8)
menghemat beberapa byte.C (gcc) endian agnostik, tidak ada lib standar,
9291 byteh(n)
adalah fungsi integer- digit hex tunggal.f(x,p)
membutuhkan integer danchar[8]
pointer. Hasilnya adalah 8 bytechar
data. ( Tidak diakhiri 0 kecuali penelepon melakukan itu.)Asumsi: Kumpulan karakter ASCII. 2 ini melengkapi
int
sehingga shift kanan akhirnya membawa ke bit tanda, dan mengkonversiuint32_t
keint
tidak munge bit-pola jika bit tinggi ditetapkan.int
setidaknya 32-bit. (Lebih luas mungkin membiarkannya bekerja pada komplemen 1 atau implementasi sign-magnitude C).Non-asumsi: apa pun tentang implementasi byte-order atau penandatanganan
char
.Cobalah online! termasuk pemanggil uji yang digunakan
printf("%.8s\n", buf)
untuk mencetak buffer keluaran tanpa menghentikannya 0.Tidak Disatukan:
Melakukan
n&=15;
di dalamh(x)
adalah titik impas; 6 byte ada vs. 3 masing-masing untuk&15
mengisolasi gigitan rendah di kedua situs panggilan.,
adalah titik urutan (atau setara dalam terminologi modern) sehingga aman untuk dilakukan*p++= stuff
dua kali dalam satu pernyataan ketika dipisahkan oleh,
operator.>>
pada integer yang ditandatangani adalah implementasi-didefinisikan sebagai aritmatika atau logis. GNU C mendefinisikannya sebagai pelengkap aritmatika 2. Tetapi pada mesin komplemen 2 yang mana pun, itu tidak terlalu penting karena kita tidak pernah melihat bit 0 atau pergeseran dari bit tanda. MSB asli pada akhirnya akan masuk ke byte rendah tidak berubah. Ini tidak terjadi pada tanda / besarnya, dan saya tidak yakin tentang komplemen 1.Jadi ini mungkin hanya portable untuk implementasi C 2 yang melengkapi. (Atau di mana
int
adalah lebih luas dari 32 bit sehingga sedikit 31 adalah hanya bagian dari besarnya.) Unsigned -> ditandatangani konversi juga munges sedikit-pola untuk bilangan bulat negatif, sehingga&15
padaint
hanya akan mengambil camilan dari nilai unsigned asli pada komplemen 2 ini. Sekali lagi, kecualiint
itu lebih luas dari 32-bit sehingga semua input non-negatif.Versi golf memiliki UB dari jatuh dari fungsi non-void. Bukan untuk mengembalikan nilai, hanya untuk menghindari mendeklarasikan
void
bukan defaultint
. Kompiler modern akan memutus ini dengan optimasi diaktifkan.Motivasi: Saya sedang mempertimbangkan jawaban x86 atau ARM Thumb asm, berpikir mungkin menyenangkan untuk melakukannya secara manual dalam C, mungkin untuk asm yang dihasilkan oleh kompiler sebagai titik awal. Lihat /programming/53823756/how-to-convert-a-number-to-hex untuk asm x86 yang hemat kecepatan, termasuk versi AVX512VBMI yang hanya 2 instruksi (tetapi membutuhkan vektor kontrol untuk vpmultishiftqb dan vpshufb jadi tidak akan bagus untuk golf). Biasanya diperlukan kerja ekstra untuk SIMD untuk byte-reverse ke dalam urutan pencetakan pada little-endian x86 sehingga output hex byte-terbalik ini sebenarnya lebih mudah dari biasanya.
Ide lain
Saya mempertimbangkan mengambil integer dengan referensi dan mengulangi byte-nya dengan
char*
, pada implementasi C little-endian (seperti x86 atau ARM). Tetapi saya tidak berpikir itu akan menyelamatkan banyak.Menggunakan
sprintf
untuk melakukan 1 byte pada suatu waktu, 64 byte setelah bermain golf:Tetapi jika kita menggunakan fungsi seperti printf, kita mungkin juga melakukan byte-swap dan melakukan
%x
printf dari semuanya seperti jawaban @ JL2210 .sumber
kode mesin SIMD x86 (AVX512-VBMI), 36 byte
(16 byte di antaranya adalah tabel hex lookup)
Ini adalah fungsi yang mengambil integer
xmm0
dan mengembalikan 8 byte data char ASCIIxmm0
, untuk penelepon untuk menyimpan di mana pun ia mau. (mis. ke memori video setelah interleaving dengan byte atribut, atau ke dalam string yang sedang dibangun, atau apa pun)Dari C, sebut itu seperti
__m128i retval = lehex(_mm_cvtsi32_si128(x))
dengan konvensi pemanggilan System V x86-64, atau MS Windowsvectorcall
.Total = 0x24 = 36 byte.
Lihat Bagaimana mengonversi angka menjadi hex? pada SO untuk cara kerjanya. (SSE2 untuk shift / punpck, lalu
vpermb
simpan pekerjaan yang kita perlukanpshufb
. AVX1 alih-alih SSE2 / SSSE3 juga menghindarimovaps
salinan register.)Perhatikan bahwa
punpcklbw
dengan operan sumber dalam urutan itu akan memberi kita nibble paling signifikan dari byte input rendah dalam elemen byte terendah, kemudian nibble paling signifikan dari byte sumber terendah. (Dalam jawaban SO itu, abswap
digunakan pada input untuk mendapatkan hasil dalam urutan pencetakan standar dengan hanya SSE2. Tetapi di sini kami menginginkan urutan itu: menggigit tinggi dalam elemen yang lebih rendah dalam setiap byte, tetapi masih urutan byte sedikit-endian).Jika kita memiliki lebih banyak konstanta data, kita dapat menghemat ruang mode pengalamatan dengan melakukan satu
mov edx, imm32
lalu menggunakan[rdx+16]
atau mode pengalamatan apa pun. Atauvpbroadcastb xmm0, [rdx+1]
.Tapi saya pikir hex 16-byte LUT +
vpermb
masih lebih baik daripada menerapkann>9 : n+'a'-10 : n+'0'
kondisi: yang membutuhkan 3 konstanta dan setidaknya 3 instruksi dengan AVX512BW byte-masking (bandingkan dengan maskvpaddb
, merge-maskedvpaddb
), atau lebih dengan AVX1 atau SSE2. (Lihat Bagaimana mengonversi angka menjadi hex? Pada SO untuk versi SSE2 itu). Dan setiap instruksi AVX512BW setidaknya sepanjang 6 byte (EVEX + opcode + modrm 4-byte), lebih lama dengan perpindahan dalam mode pengalamatan.Sebenarnya dibutuhkan setidaknya 4 instruksi karena kita perlu membersihkan sampah yang tinggi dengan
andps
, (atau EVEXvpandd
dengan operan memori siaran 4-byte) sebelum membandingkan. Dan masing-masing membutuhkan konstanta vektor yang berbeda. AVX512 memiliki broadcast operan memori, tetapi hanya untuk elemen 32-bit dan lebih luas. mis . operan terakhir EVEXvpaddb
hanyaxmm3/m128
, tidakxmm3/m128/m8bcst
. (Port muat Intel hanya dapat melakukan siaran 32 dan 64-bit secara gratis sebagai bagian dari load uop sehingga Intel mendesain AVX512BW untuk mencerminkan itu dan tidak dapat menyandikan operan byte atau word broadcast memory sama sekali, alih-alih memberi mereka opsi untuk lakukan siaran dword sehingga Anda masih dapat memampatkan konstanta Anda menjadi 4 byte: /.)Alasan saya menggunakan AVX512VBMI
vpermb
bukan SSSE3 / AVX1pshufb
ada dua:vpermb
mengabaikan bit pemilih yang tinggi.(v)pshufb
nol byte sesuai dengan bit tinggi dari vektor kontrol dan akan membutuhkan tambahanpand
atauandps
untuk benar-benar mengisolasi camilan. Dengan ukuran XMM / 16-byte,vpermb
hanya terlihat pada 4 bit rendah elemen kontrol-acak, yaitu bit[3:0]
dalam notasi Intel di bagian Operasi .vpermb
dapat mengambil data untuk dikocok (tabel pencarian) sebagai operan memori.(v)pshufb
Operan xmm / mem adalah vektor kendali-acak.Perhatikan bahwa AVX512VBMI hanya tersedia di CannonLake / Ice Lake sehingga Anda mungkin perlu simulator untuk menguji ini, seperti SDE Intel.
sumber
Scala ,
584036 byteCobalah online!
Masih menggunakan builtin untuk membalik byte
Int
, tetapi menggunakanformat
untuk memformatInt
sebagai Hex. Tidak perlu menelepontoHexString
.Dihidupkan parens
format
. Ini sekarang berarti bahwa argumen dapat diambil secara implisit_
.sumber
Keempat (gforth) ,
52 5140 byteCobalah online!
Penjelasan kode
sumber
Jelly , 13 byte
Cobalah online!
Program lengkap yang menggunakan integer sebagai argumennya dan mencetak string.
sumber
APL + WIN,
3634 byte2 byte disimpan dengan mengkonversi ke indeks nol
Anjuran untuk bilangan bulat:
Cobalah online! Courtesy Dyalog Classic
sumber
Excel, 91 byte
sumber
K4 ,
1211 byteLarutan:
Contoh:
Penjelasan:
Persis pertanyaan yang diajukan:
Catatan:
sumber
PHP , 31 byte
Cobalah online!
Mengambil keuntungan dari paket PHP dan membongkar , saya kemas input yang tidak ditandatangani dengan format "32 bit endian byte order" (
V
) ke dalam string biner dan kemudian membongkar dengan format "hex string, high nibble first" (H
) dan mencetak hasilnya.Ini tampaknya menjadi salah satu kasus langka di mana PHP bawaan sebenarnya lebih pendek daripada menerapkan algoritma sederhana!
sumber
pack()
/unpack()
fungsinya luar biasa untuk 0 kali Anda membutuhkannya di sebagian besar proyek PHP. Selamat, Anda menemukan penggunaannya!Arang , 11 byte
Cobalah online! Tautan adalah untuk mengucapkan versi kode. Penjelasan:
19 byte tanpa menggunakan format Python:
Cobalah online! Tautan adalah untuk mengucapkan versi kode. Penjelasan:
sumber
Perl 5 (-p), 22 byte
Cobalah online!
sumber
J , 10 byte
Cobalah online!
bagaimana
3!:3
adalah "konjungsi asing" untuk representasi hex, didokumentasikan di sini . Artinya, itu adalah builtin untuk mengkonversi ke hex. Namun, hasilnya tidak seperti yang kita inginkan. Misalnya, berlari:menghasilkan:
Arti dari baris lain dijelaskan pada halaman doc yang saya tautkan di atas. Bagaimanapun, jelas kami menginginkan 8 karakter pertama dari baris terakhir.
_1{
dapatkan baris terakhir.8{.
mendapat 8 karakter pertama dari itu.sumber
Ruby ,
3127 byteAkhirnya menjadi port dari jawaban PHP Night2 karena Ruby memiliki fungsionalitas paket / pembongkaran yang sama.
Cobalah online!
Jawaban 31 byte asli saya yang tidak memanfaatkan mode H8 unpack karena saya tidak mengetahuinya:
Cobalah online!
sumber
Windows Batch, 90 byte
Jalankan command-line dengan / v untuk mengaktifkan ekspansi yang tertunda.
sumber
x86 kode mesin 32-bit,
2421 bytechangelog: -3 byte: ganti add standar / cmp / jbe / add dengan hack DAS oleh @peter ferrie
64-bit: masih 24 byte. Mode lama menghapus opcode DAS.
Mode 16-bit: ukuran operan standar adalah 16-bit tetapi spesifikasi masalahnya pada dasarnya 32-bit. Termasuk hard-kode 8 digit hex.
Bolak-balik dengan
bswap
int-> manual kemudian hex dalam urutan standar (paling signifikan menggigit pertama, menulis digit hex ke buffer output char dalam urutan menaik). Ini menghindari perlu membuka gulungan untuk beralih urutan antara menggigit dalam byte vs melintasi byte.Dapat dipanggil
void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);
seperti x86-64 Sistem V, kecuali ini tidak berfungsi dalam mode 64-bit. (Perlu pointer output di EDI untukstosb
. Nomor input dapat dalam register selain ECX atau EAX.)size = 0x15 = 21 byte.
TIO FASM 32-bit kasus uji x86 dengan pemanggil asm yang menggunakan pemanggilan
write
sistem untuk menulis output setelah memanggilnya dua kali untuk menambahkan 2 string ke dalam buffer. Menguji semua digit hex 0..F, termasuk 9 dan A pada batas antara angka vs huruf.The
DAS
hack - x86 memiliki setengah-membawa bendera, untuk membawa keluar dari nibble rendah. Berguna untuk hal-hal BCD yang dikemas seperti instruksi DAS, dimaksudkan untuk digunakan setelah mengurangi dua bilangan bulat BCD 2 digit. Dengan nibble rendah AL yang berada di luar rentang 0-9, kami pasti menyalahgunakannya di sini.Perhatikan
if (old_AL > 99H) or (old_CF = 1)
LALUAL ← AL − 60H;
bagian dari bagian Operasi dalam manual; sbb selalu mengatur CF di sini sehingga bagian itu selalu terjadi. Itu dan kisaran ASCII untuk huruf besar adalah apa yang memotivasi pilihansub al, 0x69
cmp 0xD, 0xA
tidak mengatur CF0xD - 0x69
wraps ke AL =0xA4
sebagai input ke DAS. (Dan mengatur CF, menghapus AF)0x44
, kode ASCII untuk'D'
vs. angka:
cmp 0x3, 0xA
mengatur CF3 - 0x69 - 1
= AL = 0x99 dan mengatur CF dan AF'3'
.Mengurangkan
0x6a
dalam SBB akan menetapkan AF untuk setiap digit <= 9 sehingga semua angka mengikuti logika yang sama. Dan biarkan itu dibersihkan untuk setiap digit hex alfabet. yaitu dengan benar mengeksploitasi penanganan split 9 / A DAS.Biasanya (untuk kinerja) Anda akan menggunakan tabel pencarian untuk loop skalar, atau mungkin 2x tanpa cabang
lea
dancmp/cmov
tambahan bersyarat. Tetapial, imm8
instruksi 2-byte adalah kemenangan besar untuk ukuran kode.versi versi x86-64 : hanya bagian yang berbeda, antara
and al, 0xf
danstosb
.Perhatikan bahwa
add al, '0'
selalu berjalan, dan penambahan bersyarat hanya menambahkan perbedaan antara'a'-10
dan'0'
, untuk membuatnya hanya sebagaiif
penggantiif
/else
.Diuji dan berfungsi, menggunakan
main
penelepon yang sama dengan jawaban C saya , yang menggunakanchar buf[8]
danprintf("%.8s\n", buf)
.sumber
sys_write
dapat menampilkan string dengan panjang tetap dengan mudah. Oh menarik, saya tidak menyadari FASM di TIO membiarkan Anda membuat executable 32-bit, tidak seperti dengan NASM di mana ia tidak menghormati-felf32
. Saya lebih suka x86-64, dan jawaban ini tidak menyimpan byte dari kode 32-bit.sprintf
? Saya tidak berpikir libc memiliki fungsi string int-> berguna selain yang berbasis format-string, hanya string-> int seperti strtoul. Tapi ya, bswap / printf mungkin akan lebih pendek, jika Anda bisa mencari cara untuk menghitung byte untuk entri GOT untuk suatu fungsi di perpustakaan dinamis (selaincall [rel printf wrt ..got]
situs panggilan 6-byte ); executable yang terhubung secara statis minimal dapat secara signifikan lebih kecil dari dinamis, setidaknya ketika dibuatld
dengan default normal. Tapi saya tidak berpikir itu akan masuk akal untuk menghubungkannya secara statis tetapi tidak menghitung ukuran kodenya.