Scambia l'Endianness


20

Come molti di voi probabilmente sanno, le memorie hardware (indirizzabili in byte) possono essere divise in due categorie: little-endian e big-endian . Nelle memorie little-endian i byte sono numerati a partire da 0 all'estremità piccola (meno significativa) e in quelli big-end al contrario.

Curiosità : questi termini si basano sul libro di Jonathan Swift , Gulliver's Travels, in cui il re lillipuziano ordinò ai suoi cittadini di rompere le uova nel piccolo (quindi i piccoli endiani) e che i ribelli avrebbero rotto il loro nel grande.

Come funziona lo scambio

Supponiamo di avere un numero intero senza segno (32 bit) 12648430in memoria, in una macchina big-endian che potrebbe apparire come segue:

  addr: 0  1  2  3
memory: 00 C0 FF EE

Invertendo l'ordine dei byte otteniamo il numero intero esadecimale 0xEEFFC000che è 4009738240in decimale.

Il tuo compito

Scrivi un programma / funzione che riceve un numero intero a 32 bit senza segno in decimale e genera l'intero risultante quando si scambia l'endianness come descritto sopra.

Regole

  • Ingresso sarà sempre nel range 0di4294967295
  • L'output può essere stampato su STDOUT (le nuove righe / spazi finali vanno bene) o restituite
  • Ingresso e uscita sono in decimali
  • Il comportamento sull'input non valido non viene definito

Casi test

0 -> 0
1 -> 16777216
42 -> 704643072
128 -> 2147483648
12648430 -> 4009738240
16885952 -> 3232235777
704643072 -> 42
3735928559 -> 4022250974
4009738240 -> 12648430
4026531839 -> 4294967279
4294967295 -> 4294967295

Per una risposta alla funzione, "input e output sono in decimali" significa che è richiesta una stringa di caratteri numerici o una matrice di valori numerici? O una risposta di funzione può usare la rappresentazione del valore intero naturale del suo linguaggio, che nella maggior parte dei casi non ha assolutamente nulla a che fare con "decimale"?
aschepler

1
@aschepler Il valore intero della lingua, ad es. 42è dato in decimale ma tecnicamente è in binario in C per esempio. Ovviamente puoi digitare 0x2a, quello che volevo impedire è prendere l'input come una stringa simile "2a"o simile.
ბიმო

Correlati (dato che questa sfida è solo assicurarsi di
passare

Risposte:


25

linguaggio macchina x86_32, 3 byte

endian_swap:        # to be called with PASCAL REGISTER calling convention
0f c8    bswap eax
c3       ret

Questo è un po 'un trucco. La convenzione di chiamata del registro Pascal (vedi Wikipedia ) è un po 'come __fastcall, tranne che passa il primo parametro in eax e eax contiene anche il valore restituito. È anche pulitura della chiamata, ma poiché non utilizziamo la pila per qualcosa di diverso dal puntatore di ritorno non abbiamo bisogno di fare nulla. Questo ci consente di evitare un mov o xchg e usare direttamente bswap.


Potrebbe voler notare che bswaprichiede un 80486 o superiore :)
ceilingcat

@ceilingcat Molto vero, anche se sono sicuro che sia implicitamente il caso di molte altre soluzioni qui a causa delle restrizioni del compilatore o della toolchain!
Polinomio

10

linguaggio macchina x86_64 Linux, 5 4 byte

0:       0f cf                   bswap  %edi
2:       97                      xchg   %eax,%edi
3:       c3                      retq 

Grazie a @peter ferrie per -1.

Provalo online!


questo non è un valore di ritorno decimale. Non penso che conta. Inoltre, potresti xchg edi, eax per 4 byte.
peter ferrie il

@peterferrie Wow Stavo solo visitando il tuo sito Web leggendo le intestazioni PE!
plafoniera

7

C (gcc), 20, 29 17 byte

Suggerimento di @ hvd.

__builtin_bswap32

Provalo online!

Vecchia risposta;

#include<byteswap.h>
bswap_32

include dovrebbe essere importato.


6

Japt , 10 14 byte

sG ùT8 ò w ¬nG

Provalo


Spiegazione

Converti un numero intero di input in una stringa base-16 ( sG), usa 0per riempire l'inizio di lunghezza 8 ( ùT8), diviso in una matrice di 2 stringhe di caratteri ( ò), reverse ( w), ricongiungi a una stringa ( ¬) e converti indietro in base- 10 ( nG).


Sai, ciò che potrebbe essere utile è avere più funzioni del genere y, quando una funzione viene assegnata a una funzione, applica la sua normale trasformazione, esegue la funzione e quindi inverti la trasformazione. In questo caso, penso che ciò consentirebbe di accorciarlo a sG_ò w ¬8 byte. O se òanche quello fosse, potrebbe anche essere sG_ò2_wper 7 ...
ETHproductions

@ETHproductions Lo sostengo; il sotto- &.avverbio in J fa questo ed a volte è davvero utile nel golf. La codifica in tutte le inversioni potrebbe essere noiosa, però.
Cole

@ETHproductions: più "sovraccarico", meglio è :) L'ho scritto mentre tiravo le pinte e inizialmente sG_òw...non potevo, per la mia vita, capire perché non avrebbe funzionato! Alla fine ho realizzato i miei errori!
Shaggy,

Non sembra funzionare per input meno di 2 << 24 ...
Neil,

Grazie, @Neil; lo riparerà più tardi. Sembra che mi costerà 4 byte.
Shaggy,



5

APL + WIN 14 byte

256⊥⌽(4⍴256)⊤⎕

Spiegazione

⎕ prompt for screen input
(4⍴256)⊤ 4 byte representation in base 256
⌽ reverse bytes
256⊥ bytes from base 256 to integer

1
Funzionerebbe 256⊥⌽⎕⊤⍨4⍴256per -1 byte?
Erik the Outgolfer,

L'operatore ⍨ non è disponibile in APL + WIN, quindi la risposta è no, ma potrebbe anche essere sì per Dyalog APL
Graham,

5

C # , 70 68 byte

Questo probabilmente non è ottimale.

68:

Func<uint,uint>f=n=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;

70:

uint e(uint n){n=n>>16|n<<16;return(n&0xFF00FF00)>>8|(n&0xFF00FF)<<8;}

Provalo online!


È possibile spostare l'assegnazione returnnell'espressione e quindi utilizzare la sintassi del membro con espressione: uint e(uint n)=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;per 64 byte.
hvd,

@hvd Questo non viene mostrato come sintassi valida per il mio corpo. Sono stato comunque in grado di utilizzare il trucco di riorganizzazione del cambio per radere 2 byte.
Polinomio,

Ho copiato e incollato dal mio commento nel tuo link TIO per assicurarmi che non ci fossero errori di battitura o qualcosa del genere ed esattamente come è nel mio commento, funziona: TIO link
hvd

Ho notato che 0xFF00FF00 è il complemento di 0xFF00FF e mi chiedo se puoi approfittarne? Ma dichiararla una variabile richiede troppi caratteri
PrincePolka il

Oh! Buono a controllare davvero le costanti: puoi usarlo 0xFF00FFdue volte >>ing prima di &ing, e puoi quindi accorciare 0xFF00FFa ~0u/257: uint e(uint n)=>((n=n>>16|n<<16)>>8&~0u/257)|(n&~0u/257)<<8;per 60. TIO link
hvd


4

05AB1E , 12 10 byte

3F₁‰R`})₁β

Provalo online! Spiegazione:

  ₁         Integer constant 256
   ‰        [Div, Mod]
    R       Reverse
     `      Flatten to stack
3F    }     Repeat 3 times
       )    Collect results
        ₁β  Convert from base 256

1
Questa non sembra essere una soluzione valida. Il "padding" che stai facendo è in realtà la ripetizione dell'elenco dei byte per la lunghezza 4.
Erik the Outgolfer

@EriktheOutgolfer Bah, vorrei che la documentazione dicesse effettivamente che ...
Neil

3

JavaScript (ES6), 45 43 byte

f=(n,p=0,t=4)=>t?f(n>>>8,p*256+n%256,t-1):p

1
A partire da t=0salva 2 byte:f=(n,p=t=0)=>t++<4?f(n>>>8,p*256+n%256):p
Arnauld


3

MATL , 12 10 byte

7Y%1Z%P7Z%

Provalo online! O verifica tutti i casi di test .

Spiegazione

        % Implicitly input a number, read as a double
7Y%     % Cast to uint32
1Z%     % Convert to uint8 without changing underlying data. The result is 
        % an array of four uint8 numbers, each corresponding to a byte of
        % the original number's representation 
P       % Flip array
7Z%     % Convert back to uint32 without changing underlying data. The array
        % of four uint8 numbers is interpreted as one uint32 number.
        % Implicitly display

2

JavaScript (ES6), 51 45 byte

6 byte salvati con l'aiuto di @ Neil

n=>(n>>>24|n>>8&65280|(n&65280)<<8|n<<24)>>>0

Casi test


Bello, il meglio che potevo ottenere con la ricorsione era f=(n,p=0,t=4)=>t?f(n/256|0,p*256+n%256,t-1):p.
ETHproductions

@ETHproductions ... è più breve?
Erik the Outgolfer,

1
@ETHproductions È decisamente più breve. Dovresti pubblicarlo.
Arnauld,

46 byte:n=>(n>>>24|n>>8&65280|n<<8&16711680|n<<24)>>>0
Neil,

1
@hvd Nessun problema. Puoi aggiungerlo come versione alternativa o sostituire completamente quello esistente. Sta a te!
Arnauld,

2

J, 16 byte

|.&.((4#256)#:])

Provalo online!

Lavorando per abbreviare l'espressione della mano destra. Penso di poter radere qualche byte facendo funzionare questo con una versione beta J. Giuro che ho visto qui che puoi terminare un treno con un sostantivo in una nuova versione beta ...

Spiegazione

|.&.((4#256)#:])
    ((4#256)#:])  Convert to 4 two-byte blocks
            #:      Debase to
      4#256         4 digits base 256
  &.              Apply right function, left function, then inverse of right
|.                Reverse digits

Convertire a 4 cifre in base 256, invertire le cifre, quindi riconvertire in decimale. Fondamentalmente, eseguire l'algoritmo fornito nell'OP. Questa è forse la volta in cui è utile che la conversione della base mista di J richieda di specificare il numero di cifre, sebbene sarebbero 2 byte in meno se potessi terminare il treno in un sostantivo ( (#:~4#256)invece).


2

Excel VBA, 103 92 byte

La funzione di finestra immediata VBE anonima che accetta l'input dall'intervallo viene [A1]convertita in esadecimale, inverte i byte e restituisce la finestra immediata VBE

h=[Right(Rept(0,8)&Dec2Hex(A1),8)]:For i=0To 3:s=s+Mid(h,7-2*i,2):Next:[B1]=s:?[Hex2Dec(B1)]

Posso provarlo da qualche parte? Potresti aggiungere un interprete online, per favore?
ბიმო

2
@BruceForte No, sfortunatamente non ci sono interpreti online per nessuna delle varianti di VBA, tuttavia, se hai una copia di Excel sul tuo computer, puoi accedere a VBE premendo Alt + F11, quindi la finestra immediata premendo Ctrl + G. Per questa funzione anonima, incolleresti il ​​tuo input nella cella A1 e il codice sopra nella finestra immediata e premi invio
Taylor Scott

Oh - e a volte VBA è un po 'funky (e la versione Mac è imperativamente peggiore della versione Windows) quindi questo, e se non diversamente specificato, le soluzioni VBA assumono la versione predefinita di Windows a 32 bit
Taylor Scott

2

Assembly PPC (32 bit), 8 byte

endian_swap:    # WORD endian_swap(WORD)
7c 60 1c 2c     LWBRX 3,0,3
4e 80 00 20     BLR

Come funziona:

  • La convenzione di chiamata PPC inserisce il primo parametro della parola a 32 bit in SP + 24 e le ombre che indirizzano in GPR3.
  • LWBRX prende carico GPR3 ​​(terzo operando) e lo estende a zero (secondo operando) in EA, quindi legge 4 byte in ordine inverso e lo memorizza in GPR3 ​​(primo operando).
  • GPR3 contiene il valore restituito.
  • BLR ritorna dalla funzione (si dirama verso l'indirizzo nel registro LR)

Sfortunatamente non ci sono emulatori di assemblaggio PPC online che potrei trovare per dimostrare. Scusate!


2

Befunge, 62 61 o 49 byte

0&0v!p22:/3g22/*:*82\+%*:*82+<
@.$_:28*:*%00p\28*:**00g28*:*^

Provalo online!

Questo utilizza Befunge standard sull'interprete di riferimento e quindi dobbiamo tenere conto del fatto che le celle di memoria sono firmate a 8 bit e corrette per eventuali overflow con segno.

Sulle implementazioni con celle di memoria senza segno (ad es. PyFunge) o dove l'intervallo è maggiore di 8 bit (ad es. FBBI), possiamo cavarcela senza quei controlli, risparmiando 12 byte.

0&0v!p22:/3g22/*:*82\+g<
@.$_:28*:*%00p\28*:**00^

Prova FBBI online!
Prova PyFunge online!

Sebbene si noti che PyFunge ha un bug che elabora l'input intero, quindi durante il test su TIO è necessario seguire il numero nel campo di input con uno spazio o un'interruzione di riga.


2

Ottava , 10 byte

@swapbytes

Provalo online!

Questa potrebbe essere la prima volta che Octave ottiene lo stesso punteggio esatto del suo derivato golfistico, MATL. Ovviamente, in questo caso, è Octave che ha il built-in, piuttosto che MATL, che lo rende molto più facile.

Definisce un handle per il built-in swapbytes, che accetta qualsiasi tipo di dati, scambia l'endianness e genera il risultato. In questo caso, l'ingresso è un numero intero senza segno a 32 bit.



2

R , 86 byte

Pensavo che ci fosse già una risposta (o due) in R per questa domanda, ma dovevo essermi sbagliato o avevano gli stessi problemi che avevo con R che non eseguiva ints firmati. Quel problema ha eliminato tutti i builtin che avrebbero potuto aiutare. Ho provato la conversione di 256 base, ma alla fine è stata troppo lunga, ma penso che ci sia ancora spazio per qualcuno più intelligente di me per farlo. Poi ho finito per seguire una conversione di base 2 scambiando l'ordine in una funzione ricorsiva.

f=function(x,y=0,i=31)'if'(i+1,f(x-(2^i*z),y+(2^((3-i%/%8)*8+i%%8)*(z=2^i<=x)),i-1),y)

Provalo online!

f=function(x,y=0,i=31)       # set up the function and initial values
  'if'(i+1,                  # test for i >= 0
    f(                       # recursively call the function
      x-(2^i*z),             # remove 2^i from x when 2^i <= x
      y+(2^                  # add to y 2 to the power of
        ((3-i%/%8)*8+i%%8)   # calc to swap the order of the bytes
        *(z=2^i<=x)),        # when 2^i <= x
      i-1),                  # decrement i
   y)                        # return y

avevi ragione sul fatto che la base 256 fosse più corta!
Giuseppe,

@Giuseppe, hai intenzione di alzare il cappello, vero
MickyT,

2

R , 41 byte

function(n)n%/%256^(0:3)%%256%*%256^(3:0)

Provalo online!

Verifica tutti i casi di test!

Utilizza una conversione di base 256 come suggerito MickyT qui . R non ha numeri interi a 32 bit senza segno, né numeri interi a 64 bit. Questo ci impedisce di usare le operazioni bit per bit ma questo approccio (e probabilmente quello di MickyT) è probabilmente ancora più breve poiché gli operatori bit per bit di R sono abbastanza dettagliati.

Utilizza il numero 4 di questo suggerimento , tenendo conto del fatto che non avremo mai un numero così grande 256^4.

n%/%256^(0:3)%%256estrae i byte e %*%, il prodotto matrice, è il prodotto punto in questa situazione, con 256^(3:0)effetto sull'ordine inverso dei byte. %*%restituirà un 1x1 matrixcontenente il valore invertito endian.


1

Assemblaggio CP-1610 , 6 DECLE = 8 byte

Questo codice deve essere eseguito su un Intellivision .

Un codice operativo CP-1610 è codificato con un valore di 10 bit, noto come "DECLE". Questa funzione è lunga 6 DECLE, a partire da $ 480C e terminando a $ 4811.

Il CP-1610 ha registri a 16 bit, quindi ne stiamo usando due (R0 e R1) per memorizzare un valore a 32 bit.

                               ROMW  10           ; use 10-bit ROM

                               ORG   $4800        ; start program at address $4800

                               ;; example call
4800  0001                     SDBD               ; load 0xDEAD into R0
4801  02B8 00AD 00DE           MVII  #$DEAD, R0
4804  0001                     SDBD               ; load 0xBEEF into R1
4805  02B9 00EF 00BE           MVII  #$BEEF, R1

4808  0004 0148 000C           CALL  swap32       ; call our function

480B  0017                     DECR  PC           ; loop forever

                               ;; swap32 function
                       swap32  PROC

480C  0040                     SWAP  R0           ; 16-bit SWAP of R0
480D  0041                     SWAP  R1           ; 16-bit SWAP of R1

480E  01C1                     XORR  R0, R1       ; exchange R0 and R1
480F  01C8                     XORR  R1, R0       ; using 3 consecutive eXclusive OR
4810  01C1                     XORR  R0, R1

4811  00AF                     JR    R5           ; return

                               ENDP

Discarica di esecuzione

 R0   R1   R2   R3   R4   R5   R6   R7    CPU flags  instruction
 ------------------------------------------------------------------
 0000 4800 0000 0000 01FE 1041 02F1 4800  ------iq   SDBD
 0000 4800 0000 0000 01FE 1041 02F1 4801  -----D-q   MVII #$DEAD,R0
 DEAD 4800 0000 0000 01FE 1041 02F1 4804  ------iq   SDBD
 DEAD 4800 0000 0000 01FE 1041 02F1 4805  -----D-q   MVII #$BEEF,R1
[DEAD BEEF]0000 0000 01FE 1041 02F1 4808  ------iq   JSR  R5,$480C

 DEAD BEEF 0000 0000 01FE 480B 02F1 480C  ------iq   SWAP R0
 ADDE BEEF 0000 0000 01FE 480B 02F1 480D  S------q   SWAP R1
 ADDE EFBE 0000 0000 01FE 480B 02F1 480E  S------q   XORR R0,R1
 ADDE 4260 0000 0000 01FE 480B 02F1 480F  ------iq   XORR R1,R0
 EFBE 4260 0000 0000 01FE 480B 02F1 4810  S-----iq   XORR R0,R1
[EFBE ADDE]0000 0000 01FE 480B 02F1 4811  S-----iq   MOVR R5,R7

 EFBE ADDE 0000 0000 01FE 480B 02F1 480B  ------iq   DECR R7

Perché si tratta di 7,5 byte? Penso che dovrebbe essere di 8 byte.
Erik the Outgolfer,

@EriktheOutgolfer Abbastanza giusto. Aggiornato di conseguenza.
Arnauld,

@EriktheOutgolfer Perché 60 bit equivalgono a 7,5 byte?
Jeppe Stig Nielsen,

@JeppeStigNielsen È vero, ma un file non può mai essere lungo 7,5 byte, sarà pre o post-riempito con 0s.
Erik the Outgolfer,

@EriktheOutgolfer Tecnicamente, questo potrebbe davvero essere archiviato in una ROM a 10 bit. Ecco un esempio di foglio delle specifiche. (Oggi utilizziamo la ROM a 16 bit per i giochi homebrew di Intellivision, ma in passato i chip di memoria erano così costosi che l'utilizzo di 10 bit era un vero risparmio di denaro.)
Arnauld,

1

C # (.NET Core) , 72 + 31 = 103 byte

m=>BitConverter.ToUInt32(BitConverter.GetBytes(m).Reverse().ToArray(),0)

Provalo online!

+31 per using System;using System.Linq;

Speravo di usare in Array.Reverselinea, ma non lo era (vedi alternativa sotto).

C # (.NET Core) , 87 + 13 = 100 byte

m=>{var a=BitConverter.GetBytes(m);Array.Reverse(a);return BitConverter.ToUInt32(a,0);}

Provalo online!

+13 per using System;

Questa soluzione cura di @JeppeStigNielsen; rimuovendo la restrizione di avere tutto in linea salvato 3 byte.


Poiché è possibile salvare using System.Linq;, può comunque essere più economico da utilizzare x=>{var a=BitConverter.GetBytes(x);Array.Reverse(a);return BitConverter.ToUInt32(a,0);}.
Jeppe Stig Nielsen,

1

REXX , 42 byte

say c2d(left(reverse(d2c(arg(1))),4,'0'x))

Provalo online!

Ungolfed:

n=arg(1) -- take n as argument
n=d2c(n) -- convert from decimal to character (bytes)
n=reverse(n) -- reverse characters
n=left(n,4,'0'x) -- extend to four bytes, padding with zeros
n=c2d(n) -- convert from bytes to decimal again
say n -- output result


1

Linguaggio macchina ARM Linux, 8 byte

0:       e6bf0f30       rev     r0, r0
4:       e12fff1e       bx      lr

Per provare tu stesso, compila ed esegui quanto segue su un dispositivo Raspberry Pi o Android con GNUroot

#include<stdio.h>
#define f(x) ((unsigned int(*)(unsigned int))"0\xf\xbf\xe6\x1e\xff/\xe1")(x)
int main(){
  printf( "%u %u\n", 0, f(0) );
  printf( "%u %u\n", 1, f(1) );
  printf( "%u %u\n", 42, f(42) );
  printf( "%u %u\n", 128, f(128) );
  printf( "%u %u\n", 16885952, f(16885952) );
  printf( "%u %u\n", 704643072, f(704643072) );
  printf( "%u %u\n", 3735928559U, f(3735928559U) );
  printf( "%u %u\n", 4009738240U, f(4009738240U) );
  printf( "%u %u\n", 4026531839U, f(4026531839U) );
  printf( "%u %u\n", 4294967295U, f(4294967295U) );
}



1

K4 , 18 byte

Soluzione:

0b/:,/8#|12 8#0b\:

Esempi:

q)\
  0b/:,/8#|12 8#0b\:0
0
  0b/:,/8#|12 8#0b\:1
16777216
  0b/:,/8#|12 8#0b\:42
704643072
  0b/:,/8#|12 8#0b\:4294967295
4294967295
  0b/:,/8#|12 8#0b\:4026531839
4294967279

Spiegazione:

Non ci sono ints non firmati, quindi accetta input a lungo.

Converti in array booleano (64 bit), rimodella, inverti, accetta i primi 8 byte, converti in long.

0b/:,/8#|12 8#0b\: / the solution
              0b\: / convert to bits
         12 8#     / reshape into 12x8 grid (wraps)
        |          / reverse
      8#           / take first 8
    ,/             / flatten
0b/:               / convert to long

Bonus:

Versione a 19 byte in oK che puoi provare online!

2/,/8#|12 8#(64#2)\
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.