Troque o Endianness


20

Como muitos de vocês provavelmente sabem, as memórias de hardware (endereçáveis ​​por bytes) podem ser divididas em duas categorias - little-endian e big-endian . Nas memórias little-endian, os bytes são numerados começando com 0 no extremo menor (menos significativo) e nas big-endian ao contrário.

Curiosidade : esses termos são baseados no livro de Jonathan Swift , Gulliver's Travels, onde o rei liliputiano ordenou que seus cidadãos quebrassem seus ovos no finalzinho (portanto, os pequenos-finalistas) e os rebeldes os quebrariam no final grande.

Como a troca funciona

Suponha que tenhamos um número inteiro não assinado (32 bits) 12648430na memória, em uma máquina big-endian com a seguinte aparência:

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

Ao inverter a ordem dos bytes, obtemos o número inteiro hexadecimal 0xEEFFC000que é 4009738240decimal.

Sua tarefa

Escreva um programa / função que receba um número inteiro de 32 bits não assinado em decimal e produz o número inteiro resultante ao trocar a endianidade conforme descrito acima.

Regras

  • A entrada estará sempre na faixa 0de4294967295
  • A saída pode ser impressa em STDOUT (novas linhas / espaços à direita são bons) ou retornada
  • Entrada e saída estão em decimal
  • O comportamento na entrada inválida é deixado indefinido

Casos de teste

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

Para uma resposta de função, "entrada e saída são decimais" significa que é necessária uma sequência de caracteres de dígitos ou uma matriz de valores de dígitos? Ou uma resposta de função pode usar a representação do valor inteiro natural de sua linguagem, que na maioria dos casos não tem absolutamente nada a ver com "decimal"?
aschepler

1
@aschepler O valor inteiro do idioma, por exemplo. 42é dado em decimal, mas tecnicamente é em binário em C, por exemplo. É claro que você pode digitar 0x2a, o que eu queria impedir é aceitar a entrada como uma string "2a"ou algo parecido.
ბიმო

Relacionados (como este desafio é apenas certificando-se de almofada para 32 bits primeiro)
FlipTack

Respostas:


25

linguagem de máquina x86_32, 3 bytes

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

Isso é meio trapaceiro. A convenção de chamada do registro Pascal (consulte a Wikipedia ) é um pouco como __fastcall, exceto que passa o primeiro parâmetro em eax, e eax também contém o valor de retorno. Também é a limpeza de chamadas, mas como não usamos a pilha para nada além do ponteiro de retorno, não precisamos fazer nada. Isso nos permite evitar um mov ou xchg e apenas usar bswap diretamente.


Pode querer observar que bswaprequer um 80486 ou superior :)
ceilingcat

@ceilingcat Muito verdade, embora eu tenha certeza de que é implicitamente o caso de muitas outras soluções aqui devido a restrições do compilador ou da cadeia de ferramentas!
polinomial

10

linguagem de máquina x86_64 Linux, 5 4 bytes

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

Graças a @peter ferrie por -1.

Experimente online!


esse não é um valor de retorno decimal. Eu não acho que isso conta. Além disso, você pode xchg edi, eax por 4 bytes.
peter ferrie

@peterferrie Uau, eu estava navegando no seu site lendo sobre cabeçalhos de PE!
ceilingcat


6

Japonês , 10 14 bytes

sG ùT8 ò w ¬nG

Tente


Explicação

Converta o número inteiro de entrada em uma string de base 16 ( sG), use 0para preencher o início com o comprimento 8 ( ùT8), divida em uma matriz de 2 strings de caracteres ( ò), reverse ( w), junte-se a uma string ( ¬) e converta novamente em 10 ( nG).


Você sabe, o que pode ser um recurso útil é ter mais funções como yessa, quando uma função é atribuída a uma função, aplica sua transformação normal, executa a função e depois inverte a transformação. Nesse caso, acho que permitiria abreviá-lo sG_ò w ¬para 8 bytes. Ou se òfizesse isso também, poderia ser sG_ò2_wpor 7 ...
ETHproductions

@ETHproductions eu apoio; o sub- &.advérbio em J faz isso e às vezes é realmente útil no golfe. A codificação de todas as inversões pode ser entediante.
cole

@ETHproductions: quanto mais "sobrecarregar", melhor :) Eu escrevi isso enquanto puxava pintas e, originalmente sG_òw..., não conseguia, para a minha vida, descobrir por que não funcionaria! Eu percebi meu (s) erro (s) eventualmente!
Salsicha

Parece não funcionar para entradas menores que 2 << 24 ...
Neil

Obrigado, @Neil; consertará isso mais tarde. Parece que vai me custar 4 bytes.
Shaggy



5

APL + WIN 14 bytes

256⊥⌽(4⍴256)⊤⎕

Explicação

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

1
Iria 256⊥⌽⎕⊤⍨4⍴256trabalhar para -1 byte?
Erik the Outgolfer

O operador ⍨ não está disponível no APL + WIN, portanto, a resposta é não, mas poderia muito bem ser para Dyalog APL
Graham

5

C # , 70 68 bytes

Provavelmente isso não é o ideal.

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;}

Experimente online!


Você pode mover a atribuição para a returnexpressão e, em seguida, usar a sintaxe do membro com expressão corporal: uint e(uint n)=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;para 64 bytes.
hvd 26/11

@hvd Isso não está aparecendo como sintaxe válida de expressão corporal para mim. No entanto, eu era capaz de usar o truque de rearranjo de mudança para raspar 2 bytes.
Polinomial

Copiei e colei do meu comentário no seu link TIO para se certificar de que não havia erros de digitação ou qualquer coisa assim e exatamente do jeito que está no meu comentário, ele funciona: ligação TIO
HVD

Notei que 0xFF00FF00 é o complemento de 0xFF00FF e me pergunto se você pode tirar proveito disso? Mas declará-la uma variável leva muitos personagens
PrincePolka

Oh! Bom para verificar as constantes fato: você pode usar 0xFF00FFduas vezes por >>ing antes &ing, e então você pode encurtar 0xFF00FFa ~0u/257: uint e(uint n)=>((n=n>>16|n<<16)>>8&~0u/257)|(n&~0u/257)<<8;para 60. ligação TIO
HVD


4

05AB1E , 12 10 bytes

3F₁‰R`})₁β

Experimente online! Explicação:

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

1
Isso não parece ser uma solução válida. O "preenchimento" que você faz é realmente repetir a lista de bytes no comprimento 4.
Erik o Outgolfer

@EriktheOutgolfer Bah, eu gostaria que a documentação seria realmente dizer que ...
Neil

3

JavaScript (ES6), 45 43 bytes

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

1
Começando com t=0salva 2 bytes:f=(n,p=t=0)=>t++<4?f(n>>>8,p*256+n%256):p
Arnauld 25/11


3

MATL , 12 10 bytes

7Y%1Z%P7Z%

Experimente online! Ou verifique todos os casos de teste .

Explicação

        % 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 bytes

Salvo 6 bytes com a ajuda de @ Neil

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

Casos de teste


Bom, o melhor que pude obter com a recursão foi f=(n,p=0,t=4)=>t?f(n/256|0,p*256+n%256,t-1):p.
ETHproductions

@ETHproductions ... é mais curto?
Erik the Outgolfer

1
@ETHproductions Isso é definitivamente mais curto. Você deve publicá-lo.
Arnauld

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

1
@hvd Não se preocupe. Você pode adicioná-lo como uma versão alternativa ou substituir totalmente a existente. Você decide!
Arnauld

2

J, 16 bytes

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

Experimente online!

Trabalhando em reduzir a expressão da mão direita. Eu acho que posso economizar alguns bytes, fazendo isso funcionar com uma versão beta J. Juro que vi aqui que você pode terminar um trem com um substantivo em uma nova versão beta ...

Explicação

|.&.((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

Converta em 4 dígitos base 256, inverta os dígitos e depois converta novamente em decimal. Basicamente, execute o algoritmo fornecido no OP. Talvez seja a única vez em que é útil que a conversão de base mista de J exija que você especifique o número de dígitos, embora sejam 2 bytes a menos se eu pudesse terminar o trem em um substantivo (em (#:~4#256)vez disso).


2

Excel VBA, 103 92 bytes

A função de janela imediata VBE anônima que recebe a entrada do intervalo é [A1]convertida em hexadecimal, inverte bytes e gera saída para a janela imediata do 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 testar isso em algum lugar? Você poderia adicionar um intérprete online, por favor?
ბიმო

2
@BruceForte Não, infelizmente não existem interpretadores online para nenhuma das variantes do VBA; no entanto, se você possui uma cópia do Excel no seu computador, pode acessar o VBE pressionando Alt + F11 e, em seguida, a janela imediata pressionando Ctrl + G. Para esta função anônima, você colaria sua entrada na célula A1 e o código acima na janela imediata e pressionaria enter
Taylor Scott

Oh - e às vezes VBA é um pouco descolados (e a versão Mac é imperically pior do que a versão do Windows) para isso, e salvo disposição em contrário de tudo, soluções VBA assumem o padrão versão de 32 bits do Windows
Taylor Scott

2

Conjunto PPC (32 bits), 8 bytes

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

Como isso funciona:

  • A convenção de chamada PPC coloca o primeiro parâmetro de palavra de 32 bits no SP + 24 e as sombras que endereçam no GPR3.
  • O LWBRX pega a carga GPR3 ​​(terceiro operando) e a estende a zero (segundo operando) no EA, depois lê 4 bytes na ordem inversa e a armazena no GPR3 ​​(primeiro operando).
  • GPR3 mantém o valor de retorno.
  • BLR retorna da função (ramifica para o endereço no registro LR)

Infelizmente, não existem emuladores de montagem de PPC on-line que eu possa encontrar para demonstrar. Desculpe!


2

Befunge, 62 61 ou 49 bytes

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

Experimente online!

Isso está usando o Befunge padrão no interpretador de referência e, portanto, precisamos levar em consideração o fato de que as células de memória são assinadas em 8 bits e corrigir o possível estouro assinado.

Em implementações com células de memória não assinadas (por exemplo, PyFunge) ou onde o intervalo é maior que 8 bits (por exemplo, FBBI), podemos fugir sem essas verificações, economizando 12 bytes.

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

Experimente o FBBI online!
Experimente o PyFunge online!

Embora observe que o PyFunge possui uma entrada inteira de processamento de erros, portanto, ao testar no TIO, você precisa seguir o número no campo de entrada com uma quebra de espaço ou linha.


2

Oitava , 10 bytes

@swapbytes

Experimente online!

Talvez seja a primeira vez que o Octave tenha exatamente a mesma pontuação que seu derivado de golfe, o MATL. Obviamente, nesse caso, é a Octave que possui o built-in, e não o MATL, facilitando muito.

Define um identificador para o built-in swapbytes, que aceita qualquer tipo de dados, troca a endianness e gera o resultado. Nesse caso, a entrada é um número inteiro não assinado de 32 bits.



2

R , 86 bytes

Eu pensei que já havia uma resposta (ou duas) em R para esta pergunta, mas devo ter me enganado ou eles tiveram os mesmos problemas que eu tive com R não fazendo ints assinados. Esse problema eliminou todos os componentes internos que poderiam ter ajudado. Eu tentei a conversão de 256 bases, mas acabou demorando muito, mas acho que ainda há espaço para alguém mais inteligente do que eu fazer isso. Então eu acabei com o seguinte, que é uma conversão de base 2 trocando a ordem em uma função recursiva.

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)

Experimente 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

você estava certo sobre a base 256 ser mais baixa!
Giuseppe

@Giuseppe, você está indo para colocar um chapéu-se que você não está
MickyT

2

R , 41 bytes

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

Experimente online!

Verifique todos os casos de teste!

Usa uma conversão de base 256, conforme sugerido pelo MickyT aqui . R não possui números inteiros de 32 bits não assinados, nem números inteiros de 64 bits. Isso nos impede de usar operações bit a bit, mas essa abordagem (e provavelmente a de MickyT) provavelmente ainda é mais curta, pois os operadores bit a bit de R são bastante detalhados.

Utiliza o número 4 desta dica , levando em consideração que nunca estamos obtendo um número tão grande quanto 256^4.

n%/%256^(0:3)%%256extrai os bytes e %*%, o produto da matriz, é o produto escalar nessa situação, 256^(3:0)afetando a ordem inversa dos bytes. %*%retornará um 1x1 matrixcontendo o valor endian-invertido.


1

CP-1610Montagem , 6 DECLEs = 8 bytes

Este código deve ser executado em um Intellivision .

Um código de operação CP-1610 é codificado com um valor de 10 bits, conhecido como 'DECLE'. Essa função tem 6 DECLEs, começando em US $ 480C e terminando em US $ 4811.

O CP-1610 possui registradores de 16 bits, portanto, estamos usando dois deles (R0 e R1) para armazenar um valor de 32 bits.

                               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

Despejo de execução

 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

Por que isso é 7,5 bytes? Eu acho que deveria ser 8 bytes.
Erik o Outgolfer

@EriktheOutgolfer Fair suficiente. Atualizado em conformidade.
Arnauld

@EriktheOutgolfer Porque 60 bits é igual a 7,5 bytes?
Jeppe Stig Nielsen

@JeppeStigNielsen Isso é verdade, mas um arquivo nunca pode ter 7,5 bytes de comprimento, será pré ou pós preenchido com 0s.
Erik o Outgolfer

@EriktheOutgolfer Tecnicamente, isso poderia realmente ser armazenado em uma ROM de 10 bits. Aqui está um exemplo de folha de especificações. (Hoje, estamos usando ROM de 16 bits para jogos Intellivision homebrew, mas volta no dia, chips de memória eram tão caros que o uso de 10-bit foi uma poupança de dinheiro real.)
Arnauld

1

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

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

Experimente online!

+31 para using System;using System.Linq;

Eu esperava usar o Array.Reverseinline, mas não era (veja a alternativa abaixo).

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

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

Experimente online!

+13 para using System;

Esta solução cuida de @JeppeStigNielsen; removendo a restrição de ter tudo em linha salvo 3 bytes.


Como você pode salvar using System.Linq;, ainda pode ser mais barato usar x=>{var a=BitConverter.GetBytes(x);Array.Reverse(a);return BitConverter.ToUInt32(a,0);}.
Jeppe Stig Nielsen

1

REXX , 42 bytes

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

Experimente 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

Linguagem de máquina ARM Linux, 8 bytes

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

Para tentar você mesmo, compile e execute o seguinte em um dispositivo Raspberry Pi ou Android executando o 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 bytes

Solução:

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

Exemplos:

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

Explicação:

Como não há entradas não assinadas, a entrada é longa.

Converta em matriz booleana (64 bits), reformule, inverta, obtenha os primeiros 8 bytes e converta novamente em comprimento.

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

Bônus:

Versão de 19 bytes em OK, que você pode experimentar online!

2/,/8#|12 8#(64#2)\
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.