Einführung
Während der Arbeit mit dem BMP- Generator (Bitmap- Generator) habe ich das Problem, Zahlen in Little-Endian-Hex-Strings umzuwandeln. Hier ist eine Funktion, die ich in JavaScript erstelle - aber ich frage mich, wie kleiner Code ähnlich funktionieren kann
let liEnd= num => num.toString(16).padStart(8,'0').match(/../g).reverse().join``;
console.log(liEnd(304767)) // 304767 dec = 0x4a67f hex
Herausforderung
Schreibfunktion, die bei der Eingabe eine 32-Bit-Ganzzahl ohne Vorzeichen verwendet und eine 8-stellige hexadezimale Zeichenfolge mit kleiner Endian-Reihenfolge erzeugt. Der Beispielalgorithmus, der die Arbeit erledigt:
- konvertiere numb in hex string zB:
304767 -> '4a67f'
- Fügen Sie Füllungsnullen hinzu, um eine Zeichenfolge mit 8 Zeichen zu erhalten:
'0004a67f'
- Saite in vier 2-Zeichen-Stücke teilen:
'00','04','a6','7f'
- umgekehrte Reihenfolge der Teile
'7f','a6','04','00'
- Teile verbinden und als Ergebnis zurückkehren:
'7fa60400'
Beispiel für Ein- und Ausgabe
Die Eingangsnummer (oder Zeichenfolge mit Dez.-Nummer) befindet sich links von der Eingabe- ->
Hex-Zeichenfolge rechts
2141586432 -> 0004a67f
304767 -> 7fa60400
f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)
spart ein Byte :)R ,
5453 BytesProbieren Sie es online aus!
Jede Gruppe von 2 Zeichen ist tatsächlich die hexadezimale Darstellung einer Ziffer in der Basis 256.
scan()%/%256^(0:3)%%256
Konvertiert in eine Basis-256-Zahl mit 4 umgekehrten Ziffern,...%*%256^(3:0)
verbindet sie als einzelne Ganzzahl undformat.hexmode(...,8)
konvertiert diese Zahl in ihre hexadezimale Darstellung mit 8 Ziffern.quelle
JavaScript (ES7),
5957 ByteString-Manipulation.
Probieren Sie es online aus!
Wie?
Probieren Sie es online aus!
/\B../g
\B
Probieren Sie es online aus!
Wir
reverse()
undjoin()
um die letzte Saite zu bekommen.JavaScript (ES6), 61 Byte
Rekursive Funktion.
Probieren Sie es online aus!
quelle
Zsh , 46 Bytes
Probieren Sie es online aus!
quelle
C # (Visual C # Interactive Compiler) , 54 Byte
4 Bytes dank @PeterCordes gespeichert
Probieren Sie es online aus!
Erläuterung
quelle
4278255360
Maskenkonstante auf16711935
(0xff00ff
) verkleinern, wenn Sie vor dem Maskieren verschieben? Oder kostet das extra Parens? Wenn nicht, dann0xff00ff00
ist es gleich lang, aber für den Menschen viel bedeutungsvoller.>>
eine höhere Priorität hat als das&
, was insgesamt 4 Bytes gespart hat. Vielen Dank!Japt
-P
, 10 BytesVersuch es
quelle
-P
das-P
: Wenn die Ausgabe ein Array ist, werden Ausgaben ohne Trennzeichen (dh verbunden mitP
) ausgegeben . " Das Flag steht also für einen impliziten statt für einen expliziten Join, um Bytes zu speichern. :)C (gcc) , 30 Bytes
Probieren Sie es online aus!
quelle
Python 2 , 43 Bytes
Probieren Sie es online aus!
-4 Bytes dank benrg
Gibt eine Liste von Zeichen aus. Berechnet durch Abrufen der hexadezimalen Ziffern der Eingabe an Indizes
6, 7, 4, 5, 2, 3, 0, 1
.quelle
[i^6]for i in range(8)
spart ein paar Bytes.C (gcc) endian agnostisch, keine Standardbibliotheken,
9291 Bytesh(n)
ist eine einstellige Ganzzahl-> Hex-Hilfsfunktion.f(x,p)
nimmt eine ganze Zahl und einenchar[8]
Zeiger. Das Ergebnis sind 8 Datenbyteschar
. ( Nicht 0-terminiert, es sei denn, der Anrufer tut dies.)Annahmen: ASCII-Zeichensatz. Das 2er-Komplement,
int
so dass die Rechtsverschiebung schließlich das Vorzeichenbit verringert , und das Konvertieren von auint32_t
inint
das Bitmuster wird nicht beeinträchtigt, wenn das hohe Bit gesetzt ist.int
ist mindestens 32-Bit. (Weiter kann es bei 1-Komplement- oder C-Implementierungen mit Vorzeichengröße funktionieren).Nichtannahmen: Alles über die Reihenfolge der Implementierung oder die Signatur von
char
.Probieren Sie es online aus! einschließlich Testaufrufer
printf("%.8s\n", buf)
zum Drucken des Ausgabepuffers ohne 0-Terminierung.Ungolfed:
Doing
n&=15;
innenh(x)
ist der Break-even; 6 Bytes dort gegen jeweils 3&15
, um das niedrige Knabbern an beiden Anrufstellen zu isolieren.,
ist ein Sequenzpunkt (oder ein Äquivalent in der modernen Terminologie), daher ist es sicher,*p++= stuff
zweimal in einer Anweisung zu arbeiten, wenn dies vom,
Operator getrennt wird .>>
Eine vorzeichenbehaftete Ganzzahl wird durch die Implementierung entweder als arithmetisch oder als logisch definiert. GNU C definiert es als das Komplement der arithmetischen 2. Aber auf jeder 2er-Komplement-Maschine spielt es keine Rolle, weil wir niemals die eingeschobenen Nullen oder Kopien des Vorzeichenbits betrachten. Das ursprüngliche MSB wird schließlich unverändert in das Low-Byte gelangen. Dies ist bei Vorzeichen / Größe nicht der Fall, und ich bin mir über das Komplement von 1 nicht sicher.Dies kann also möglicherweise nur auf 2-Komplement-C-Implementierungen portierbar sein. (Oder wo
int
es breiter als 32 Bit ist, so dass Bit 31 nur ein Teil der Größe ist.) Vorzeichenlose -> vorzeichenbehaftete Konvertierung mungiert auch das Bitmuster für negative ganze Zahlen, so dass&15
einint
nur Halbbytes des ursprünglichen vorzeichenlosen Werts auf dem 2er-Komplement extrahiert. Wiederum, esint
sei denn, es war breiter als 32-Bit, sodass alle Eingänge nicht negativ sind.Bei der Golfversion fällt UB vom Ende einer nicht leeren Funktion ab. Einen Wert nicht zurückzugeben, nur um zu vermeiden, dass er
void
anstelle des Standardwerts deklariert wirdint
. Moderne Compiler werden dies mit aktivierter Optimierung unterbrechen.Motivation: Ich habe über eine x86- oder ARM Thumb asm-Antwort nachgedacht und dachte, es könnte Spaß machen, sie manuell in C auszuführen, möglicherweise für vom Compiler generierten asm als Ausgangspunkt. Unter /programming/53823756/how-to-convert-a-number-to-hex finden Sie Informationen zu geschwindigkeitseffizientem x86-ASM, einschließlich einer AVX512VBMI-Version, die nur zwei Anweisungen enthält (jedoch Kontrollvektoren für vpmultishiftqb und vpshufb benötigt) wäre also nicht toll für golf). Normalerweise erfordert SIMD zusätzliche Arbeit, um die Byte-Umkehrung in die Druckreihenfolge auf Little-Endian x86 durchzuführen, sodass diese byteumgekehrte Hex-Ausgabe tatsächlich einfacher als normal ist.
Andere Ideen
Ich habe überlegt, die Ganzzahl als Referenz zu nehmen und ihre Bytes mit
char*
einer Little-Endian-C-Implementierung (wie x86 oder ARM) zu durchlaufen. Aber ich denke nicht, dass das viel gespart hätte.Verwenden
sprintf
Sie jeweils 1 Byte, 64 Byte nach dem Golfen:Wenn wir jedoch printf-ähnliche Funktionen verwenden, können wir genauso gut einen Byte-Swap durchführen und einen
%x
printf des Ganzen wie die Antwort von @ JL2210 erstellen .quelle
x86 SIMD-Maschinencode (AVX512-VBMI), 36 Byte
(16 Bytes davon sind eine Hex-Nachschlagetabelle)
Dies ist eine Funktion, die eine Ganzzahl aufnimmt
xmm0
und 8 Byte ASCII-Zeichendaten zurückgibtxmm0
, damit der Aufrufer speichern kann, wo immer er will. (zB in den Videospeicher nach dem Verschachteln mit Attributbytes oder in eine im Aufbau befindliche Zeichenfolge oder was auch immer)Rufen Sie es in C wie
__m128i retval = lehex(_mm_cvtsi32_si128(x))
bei der x86-64-System V-Aufrufkonvention oder bei MS Windows aufvectorcall
.Gesamt = 0x24 = 36 Bytes.
Siehe Wie konvertiere ich eine Zahl in Hex? auf SO, wie das funktioniert. (SSE2 für Shift / Punpck
vpermb
spart dann die Arbeit, die wir benötigen würdenpshufb
. AVX1 anstelle von SSE2 / SSSE3 vermeidet auch einemovaps
Registerkopie.)Beachten Sie, dass
punpcklbw
mit den Quelloperanden in dieser Reihenfolge das höchstwertige Halbbyte des unteren Eingabebytes im Element mit dem niedrigsten Byte und dann das niedrigstwertige Halbbyte des niedrigsten Quellbytes erhalten wird. (In dieser SO-Antwort wird abswap
für die Eingabe verwendet, um ein Ergebnis in der Standarddruckreihenfolge mit nur SSE2 zu erhalten. Aber hier wollen wir diese Reihenfolge: hohes Halbbyte im unteren Element innerhalb jedes Bytes, aber immer noch Little-Endian-Bytereihenfolge).Wenn wir mehr Daten Konstanten hätten, könnten wir Adressieren-Modus Platz sparen , indem man tut
mov edx, imm32
dann mit[rdx+16]
oder was auch immer Adressierungsarten. Odervpbroadcastb xmm0, [rdx+1]
.Ich denke jedoch, dass eine 16-Byte-Hex-LUT +
vpermb
immer noch besser ist als die Implementierung dern>9 : n+'a'-10 : n+'0'
Bedingung: Dies erfordert 3 Konstanten und mindestens 3 Anweisungen mit AVX512BW-Bytemaskierung (vergleiche in mask ,,vpaddb
merge-vpaddb
masked) oder mehr mit AVX1 oder SSE2. (Siehe So konvertieren Sie eine Zahl in Hex? Auf SO für eine SSE2-Version davon). Und jeder AVX512BW-Befehl ist mindestens 6 Byte lang (4 Byte EVEX + Opcode + Modrm), länger mit einer Verschiebung im Adressierungsmodus.Tatsächlich würde es mindestens 4 Anweisungen erfordern, da wir vor dem Vergleich hohen Müll mit
andps
(oder EVEXvpandd
mit einem 4-Byte-Broadcast-Speicheroperanden) löschen müssen . Und jede davon benötigt eine andere Vektorkonstante. AVX512 verfügt über Broadcast-Speicheroperanden, jedoch nur für Elemente mit 32 Bit und mehr. zB EVEXvpaddb
‚s letzte Operand ist nurxmm3/m128
, nichtxmm3/m128/m8bcst
. (Intels Load-Ports können nur 32- und 64-Bit-Broadcasts im Rahmen eines Load-Uops kostenlos ausführen. Intel hat AVX512BW so konzipiert, dass dies nicht berücksichtigt wird, und kann überhaupt keine Byte- oder Word-Broadcast-Speicheroperanden codieren, anstatt ihnen die Option zu geben Führen Sie Dword-Broadcasts durch, damit Sie Ihre Konstanten weiterhin auf 4 Byte komprimieren können: /.)Ich habe AVX512VBMI
vpermb
anstelle von SSSE3 / AVX1pshufb
in zweierlei Hinsicht verwendet :vpermb
ignoriert hohe Bits der Selektoren.(v)pshufb
Null-Bytes gemäß dem hohen Bit des Steuervektors und hätte ein zusätzlichespand
oderandps
tatsächlich isoliertes Halbbyte benötigt. Bei einer XMM / 16-Byte-Größe werdenvpermb
nur die niedrigen 4 Bits der Shuffle-Steuerelemente betrachtet, dh die Bits[3:0]
in der Intel-Notation im Abschnitt Operation .vpermb
kann die zu mischenden Daten (die Nachschlagetabelle) als Speicheroperanden verwenden.(v)pshufb
Der xmm / mem-Operand ist der Shuffle-Control-Vektor.Beachten Sie, dass AVX512VBMI nur auf CannonLake / Ice Lake verfügbar ist. Daher benötigen Sie wahrscheinlich einen Simulator, um dies zu testen, wie z. B. Intels SDE.
quelle
Scala ,
584036 BytesProbieren Sie es online aus!
Verwendet immer noch das eingebaute, um die Bytes von umzukehren
Int
, aber verwendet,format
um dasInt
als Hex zu formatieren . Sie müssen nicht anrufentoHexString
.Die Parens wurden entfernt
format
. Dies bedeutet nun, dass das Argument implizit mit verwendet werden kann_
.quelle
Forth (gforth) ,
52 5140 BytesProbieren Sie es online aus!
Code-Erklärung
quelle
Gelee , 13 Bytes
Probieren Sie es online aus!
Ein vollständiges Programm, das eine Ganzzahl als Argument verwendet und eine Zeichenfolge druckt.
quelle
APL + WIN,
3634 Bytes2 Bytes werden durch Konvertieren in Index Null gespeichert
Eingabeaufforderungen für die Ganzzahl:
Probieren Sie es online aus! Mit freundlicher Genehmigung von Dyalog Classic
quelle
Excel, 91 Bytes
quelle
K4 ,
1211 BytesLösung:
Beispiele:
Erläuterung:
Ziemlich genau das, was die Frage stellt:
Anmerkungen:
quelle
PHP , 31 Bytes
Probieren Sie es online aus!
Ich nutze das Packen und Entpacken von PHP , packe die vorzeichenlose Eingabe mit dem Format "32-Bit-Little-Endian-Byte-Reihenfolge" (
V
) in eine Binärzeichenfolge und entpacke sie dann mit dem Format "Hex-Zeichenfolge, High Nibble First" (H
) und drucke das Ergebnis.Dies scheint einer der seltenen Fälle zu sein, in denen die integrierten Funktionen von PHP tatsächlich kürzer sind als die Implementierung eines einfachen Algorithmus!
quelle
pack()
/unpack()
Funktionen sind fantastisch für das 0-fache, das Sie jemals in den meisten PHP-Projekten benötigen. Herzlichen Glückwunsch, Sie haben ihre Verwendung gefunden!Holzkohle , 11 Bytes
Probieren Sie es online aus! Der Link führt zur ausführlichen Version des Codes. Erläuterung:
19 Bytes ohne Python-Formatierung:
Probieren Sie es online aus! Der Link führt zur ausführlichen Version des Codes. Erläuterung:
quelle
Perl 5 (-p), 22 Bytes
Probieren Sie es online aus!
quelle
J , 10 Bytes
Probieren Sie es online aus!
Wie
3!:3
ist eine J "Fremdkonjunktion" für die Hex-Darstellung, die hier dokumentiert ist . Das heißt, es ist eine integrierte Funktion zum Konvertieren in Hex. Es ist jedoch nicht ganz das, was wir wollen. ZB Laufen:produziert:
Die Bedeutung der anderen Zeilen wird auf der oben verlinkten Dokumentseite erläutert. Auf jeden Fall ist klar, dass wir die ersten 8 Zeichen der letzten Zeile wollen.
_1{
Holen Sie sich die letzte Zeile.8{.
bekommt die ersten 8 Zeichen davon.quelle
Ruby ,
3127 BytesAm Ende war es ein Port der PHP-Antwort von Night2, da Ruby dieselbe Pack / Unpack-Funktionalität hat.
Probieren Sie es online aus!
Meine ursprüngliche 31-Byte-Antwort, die den H8-Entpackmodus nicht nutzte, weil ich nichts davon wusste:
Probieren Sie es online aus!
quelle
Windows Batch, 90 Bytes
Führen Sie die Befehlszeile mit / v aus, um die verzögerte Erweiterung zu aktivieren.
quelle
x86 32-Bit-Maschinencode,
2421 ByteChangelog: -3 Bytes: Ersetzen Sie das Standard-Add / cmp / jbe / add durch einen DAS-Hack von @peter ferrie
64-Bit: immer noch 24 Bytes. Im Long-Modus wurde der DAS-Opcode entfernt.
16-Bit-Modus: Die Standardoperandengröße ist 16-Bit, aber die Problemspezifikation ist von Natur aus 32-Bit. Einschließlich fest codierter 8 hexadezimaler Ziffern.
Byte-Reverse mit
bswap
dann manuellem int-> hex in Standardreihenfolge (höchstwertiges Halbbyte zuerst, Schreiben von Hexadezimalziffern in aufsteigender Reihenfolge in einen Zeichenausgabepuffer ). Dadurch wird vermieden, dass die Schleife abgewickelt werden muss, um die Reihenfolge zwischen Halbbytes innerhalb eines Bytes zu wechseln. über Bytes.Aufrufbar
void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);
wie x86-64 System V, außer dass dies im 64-Bit-Modus nicht funktioniert. (Es benötigt den Ausgabezeiger in EDI fürstosb
. Die Eingangsnummer kann sich in einem anderen Register als ECX oder EAX befinden.)Größe = 0x15 = 21 Bytes.
TIO FASM 32-Bit x86-Testfall mit einem asm-Aufrufer, der einen
write
Systemaufruf verwendet, um die Ausgabe zu schreiben, nachdem er zweimal aufgerufen wurde, um 2 Zeichenfolgen an einen Puffer anzuhängen. Testet alle hexadezimalen Ziffern 0..F, einschließlich 9 und A an der Grenze zwischen Ziffer und Buchstabe.Der
DAS
Hack - x86 hat eine Half-Carry-Flagge zum Mitnehmen aus dem Low-Nibble. Nützlich für gepackte BCD-Inhalte wie den DAS-Befehl, der nach dem Subtrahieren von zwei zweistelligen BCD-Ganzzahlen verwendet werden soll. Da das niedrige Knabbern von AL außerhalb des Bereichs von 0 bis 9 liegt, missbrauchen wir es hier definitiv.Beachten Sie den
if (old_AL > 99H) or (old_CF = 1)
DANN-AL ← AL − 60H;
Teil des Bedienungsabschnitts im Handbuch. sbb setzt hier immer CF, so dass ein Teil immer passiert. Das und der ASCII-Bereich für Großbuchstaben motivieren die Wahl vonsub al, 0x69
cmp 0xD, 0xA
setzt CF nicht0xD - 0x69
in AL = umgebrochen0xA4
. (Und setzt CF, löscht AF)0x44
der ASCII-Code für übrig bleibt'D'
gegen eine Ziffer:
cmp 0x3, 0xA
setzt CF3 - 0x69 - 1
= AL = 0x99 und setzt CF und AF'3'
.Durch Subtrahieren
0x6a
in der SBB wird AF für jede Ziffer <= 9 eingestellt, sodass alle Ziffern der gleichen Logik folgen. Und lassen Sie es für jede alphabetische Hex-Ziffer frei. dh die 9 / A-Split-Behandlung von DAS korrekt ausnutzen.Normalerweise (aus Gründen der Leistung) verwenden Sie eine Nachschlagetabelle für eine Skalarschleife oder möglicherweise eine verzweigungslose 2x-
lea
undcmp/cmov
bedingte Addition. Aber 2-Byte-al, imm8
Anweisungen sind ein großer Gewinn für die Codegröße.x86-64 version version : nur der Teil, der sich zwischen
and al, 0xf
und unterscheidetstosb
.Beachten Sie, dass das
add al, '0'
immer ausgeführt wird und das bedingte Hinzufügen nur den Unterschied zwischen'a'-10
und hinzufügt'0'
, um es nur zu einemif
anstelle vonif
/ zu machenelse
.Getestet und funktioniert mit demselben
main
Anrufer wie meine C-Antwort , diechar buf[8]
und verwendetprintf("%.8s\n", buf)
.quelle
sys_write
Zeichenfolgen mit fester Länge einfach ausgeben können. Oh interessant, ich hatte nicht bemerkt, dass FASM auf TIO Sie 32-Bit-ausführbare Dateien erstellen lässt, im Gegensatz zu NASM, wo es nicht respektiert-felf32
. Ich bevorzuge sowieso x86-64, und diese Antwort speichert keine Bytes aus 32-Bit-Code.sprintf
? Ich glaube nicht, dass libc andere nützliche int-> string-Funktionen als format-stringbasierte hat, nur string-> int wie strtoul. Aber ja, bswap / printf wäre wahrscheinlich kürzer, wenn Sie herausfinden könnten, wie Bytes für den GOT-Eintrag für eine Funktion in einer dynamischen Bibliothek gezählt werden können (neben der 6-Byte-call [rel printf wrt ..got]
Aufrufstelle). Eine minimale Anzahl statisch verknüpfter ausführbarer Dateien kann erheblich kleiner als dynamisch sein, zumindest wenn sield
mit normalen Standardeinstellungen erstellt wurden. Aber ich denke nicht, dass es vernünftig wäre, es statisch zu verknüpfen, aber seine Codegröße nicht zu zählen.