Intercambia el Endianness


20

Como la mayoría de ustedes probablemente saben, las memorias de hardware (direccionables por byte) se pueden dividir en dos categorías: little-endian y big-endian . En las memorias little-endian los bytes están numerados comenzando con 0 en el extremo pequeño (menos significativo) y en los big-endian al revés.

Dato curioso : estos términos se basan en el libro de Jonathan Swift , Gulliver's Travels, donde el rey liliputiense ordenó a sus ciudadanos que rompieran sus huevos en el pequeño extremo (por lo tanto, los pequeños endianos) y los rebeldes romperían los suyos en el gran extremo.

Cómo funciona el intercambio

Supongamos que tenemos un entero sin signo (32 bits) 12648430en la memoria, en una máquina big-endian que podría tener el siguiente aspecto:

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

Al invertir el orden de bytes, obtenemos el entero hexadecimal 0xEEFFC000que está 4009738240en decimal.

Tu tarea

Escriba un programa / función que reciba un entero de 32 bits sin signo en decimal y genere el entero resultante al intercambiar el endianness como se describió anteriormente.

Reglas

  • La entrada siempre estará en el rango 0de4294967295
  • La salida puede imprimirse en STDOUT (las líneas / espacios finales están bien) o devolverse
  • La entrada y la salida están en decimal.
  • El comportamiento en la entrada inválida se deja sin definir

Casos de prueba

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

Para una respuesta de función, ¿"entrada y salida están en decimal" significa que se requiere una cadena de caracteres de dígitos o una matriz de valores de dígitos? ¿O puede una respuesta de función usar la representación del valor entero natural de su lenguaje, que en la mayoría de los casos no tiene absolutamente nada que ver con "decimal"?
aschepler

1
@aschepler El valor entero del lenguaje, por ejemplo. 42se da en decimal pero técnicamente está en binario en C, por ejemplo. Por supuesto 0x2a, puede escribir , lo que quería evitar es tomar la entrada como una cadena como "2a"o similar.
ბიმო

Relacionado (ya que este desafío es solo asegurarse de rellenar a 32 bits primero)
FlipTack

Respuestas:


25

lenguaje de máquina x86_32, 3 bytes

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

Esto es un poco tramposo. La convención de llamadas de registro Pascal (ver Wikipedia ) es un poco como __fastcall, excepto que pasa el primer parámetro en eax, y eax también contiene el valor de retorno. También es una limpieza de llamadas, pero como no usamos la pila para otra cosa que no sea el puntero de retorno, no necesitamos hacer nada. Esto nos permite evitar un mov o xchg y simplemente usar bswap directamente.


Es posible que desee tener en cuenta que bswaprequiere un 80486 o superior :)
ceilingcat

@ceilingcat Muy cierto, aunque estoy seguro de que ese es el caso implícito de muchas otras soluciones aquí debido a restricciones del compilador o de la cadena de herramientas.
Polinómico

10

x86_64 lenguaje de máquina Linux, 5 4 bytes

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

Gracias a @peter ferrie por -1.

Pruébalo en línea!


ese no es un valor de retorno decimal. No creo que eso cuente. Además, puedes xchg edi, eax por 4 bytes.
Peter Ferrie

@peterferrie ¡Guau, solo estaba navegando en su sitio web leyendo sobre encabezados de PE!
ceilingcat el


6

Japt , 10 14 bytes

sG ùT8 ò w ¬nG

Intentalo


Explicación

Convierta el entero de entrada en una cadena de base 16 ( sG), use 0para rellenar el inicio a la longitud 8 ( ùT8), divida en una matriz de cadenas de 2 caracteres ( ò), invierta ( w), vuelva a unirse a una cadena ( ¬) y vuelva a convertir a base- 10 ( nG).


Sabes, lo que podría ser una característica útil es tener más funciones como yesa, cuando se le da una función a una función, aplica su transformación normal, ejecuta la función y luego invierte la transformación. En este caso, creo que eso permitiría acortarlo a sG_ò w ¬8 bytes. O si òhiciera eso también, incluso podría ser sG_ò2_wpor 7 ...
ETHproductions

@ETHproductions lo apoyo; el sub- &.adverbio en J hace esto y a veces es realmente útil en el golf. Sin embargo, la codificación en todas las inversiones puede ser tediosa.
cole

@ETHproductions: cuanto más "sobrecarga", mejor :) Escribí esto mientras sacaba pintas y originalmente sG_òw...no pude, por mi vida, descubrir por qué no funcionaría. ¡Me di cuenta de mis errores eventualmente!
Shaggy

No parece funcionar para entradas de menos de 2 << 24 ...
Neil

Gracias, @Neil; lo arreglará más adelante. Parece que me costará 4 bytes.
Shaggy



5

APL + WIN 14 bytes

256⊥⌽(4⍴256)⊤⎕

Explicación

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

1
¿ 256⊥⌽⎕⊤⍨4⍴256Funcionaría para -1 byte?
Erik the Outgolfer

El operador ⍨ no está disponible en APL + WIN, por lo que la respuesta es no, pero podría ser sí para Dyalog APL
Graham el

5

C # , 70 68 bytes

Esto probablemente no sea óptimo.

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

Pruébalo en línea!


Puede mover la asignación a la returnexpresión y luego usar la sintaxis de miembro con cuerpo de expresión: uint e(uint n)=>((n=n>>16|n<<16)&0xFF00FF00)>>8|(n&0xFF00FF)<<8;para 64 bytes.
hvd

@hvd Eso no se muestra como una sintaxis de cuerpo de expresión válida para mí. Sin embargo, pude usar el truco de cambio de reordenamiento para eliminar 2 bytes.
Polinómico el

Copié y pegué mi comentario en su enlace TIO para asegurarme de que no hubiera errores tipográficos ni nada por el estilo y exactamente como está en mi comentario, funciona: Enlace TIO
hvd

Me di cuenta de que 0xFF00FF00 es el complemento de 0xFF00FF y me pregunto si puedes aprovechar eso. Pero declararlo como una variable requiere demasiados caracteres
PrincePolka

Oh! Es bueno verificar las constantes de hecho: puede usar 0xFF00FFdos veces >>ing antes de &ing, y luego puede acortar 0xFF00FFa ~0u/257: uint e(uint n)=>((n=n>>16|n<<16)>>8&~0u/257)|(n&~0u/257)<<8;por 60. Enlace TIO
hvd


4

05AB1E , 12 10 bytes

3F₁‰R`})₁β

Pruébalo en línea! Explicación:

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

1
Esto no parece ser una solución válida. El "relleno" que haces es en realidad repetir la lista de bytes a la longitud 4.
Erik the Outgolfer

@EriktheOutgolfer Bah, desearía que la documentación realmente dijera eso ...
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
A partir de t=0guardar 2 bytes:f=(n,p=t=0)=>t++<4?f(n>>>8,p*256+n%256):p
Arnauld


3

MATL , 12 10 bytes

7Y%1Z%P7Z%

Pruébalo en línea! O verificar todos los casos de prueba .

Explicación

        % 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

Guardado 6 bytes con la ayuda de @ Neil

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

Casos de prueba


Bien, lo mejor que pude obtener con la recursividad fue f=(n,p=0,t=4)=>t?f(n/256|0,p*256+n%256,t-1):p.
ETHproductions

@ETHproductions ... ¿eso es más corto?
Erik the Outgolfer

1
@ETHproductions Eso es definitivamente más corto. Deberías publicarlo.
Arnauld el

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

1
@hvd No te preocupes. Puede agregarlo como una versión alternativa o reemplazar completamente la existente. ¡Depende de usted!
Arnauld

2

J, 16 bytes

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

Pruébalo en línea!

Trabajando para acortar la expresión de la mano derecha. Creo que puedo reducir algunos bytes haciendo que esto funcione con una versión beta J. Juro que vi aquí que puedes terminar un tren con un sustantivo en una nueva versión beta ...

Explicación

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

Convierta a 4 dígitos base 256, invierta los dígitos, luego vuelva a convertir a decimal. Básicamente, realice el algoritmo que se proporciona en el OP. Esta es quizás la única vez en la que es útil que la conversión de base mixta de J requiera que especifiques la cantidad de dígitos, aunque sería 2 bytes menos si pudiera terminar el tren en un sustantivo (en su (#:~4#256)lugar).


2

Excel VBA, 103 92 Bytes

La función de ventana inmediata anónima de VBE que toma la entrada del rango se [A1]convierte en hexadecimal, invierte bytes y sale a la ventana inmediata de 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)]

¿Puedo probar esto en alguna parte? ¿Podría agregar un intérprete en línea, por favor?
ბიმო

2
@BruceForte No, desafortunadamente no hay intérpretes en línea para ninguna de las variantes de VBA, sin embargo, si tiene una copia de Excel en su computadora, puede acceder al VBE presionando Alt + F11, y luego la ventana inmediata presionando Ctrl + G. Para esta función anónima, debe pegar su entrada en la celda A1 y el código de arriba en la ventana inmediata y presionar enter
Taylor Scott

Ah, y a veces VBA es un poco raro (y la versión de Mac es imperiosamente peor que la versión de Windows), así que, a menos que se indique lo contrario, las soluciones de VBA asumen la versión predeterminada de Windows de 32 bits
Taylor Scott

2

Ensamblaje PPC (32 bits), 8 bytes

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

Cómo funciona esto:

  • La convención de llamada PPC coloca el primer parámetro de palabra de 32 bits en SP + 24 y sombrea esa dirección en GPR3.
  • LWBRX toma la carga GPR3 ​​(tercer operando) y la extiende a cero (segundo operando) en EA, luego lee 4 bytes en orden inverso y la almacena en GPR3 ​​(primer operando).
  • GPR3 contiene el valor de retorno.
  • BLR regresa de la función (se bifurca a la dirección en el registro LR)

Desafortunadamente, no hay ningún emulador de ensamblaje PPC en línea que pueda encontrar para demostrar. ¡Lo siento!


2

Befunge, 62 61 o 49 bytes

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

Pruébalo en línea!

Esto está utilizando Befunge estándar en el intérprete de referencia y, por lo tanto, debemos tener en cuenta el hecho de que las celdas de memoria están firmadas de 8 bits y corrigen el posible desbordamiento firmado.

En implementaciones con celdas de memoria sin firmar (por ejemplo, PyFunge), o donde el rango es mayor a 8 bits (por ejemplo, FBBI), podemos escapar sin esas comprobaciones, ahorrando 12 bytes.

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

¡Prueba FBBI en línea!
¡Prueba PyFunge en línea!

Aunque tenga en cuenta que PyFunge tiene una entrada entera de procesamiento de errores, por lo que al probar en TIO debe seguir el número en el campo de entrada con un espacio o salto de línea.


2

Octava , 10 bytes

@swapbytes

Pruébalo en línea!

Esta puede ser la primera vez que Octave tiene exactamente el mismo puntaje que su derivado de golf, MATL. Por supuesto, en este caso, es Octave el que tiene incorporado, en lugar de MATL, lo que lo hace mucho más fácil.

Define un identificador para el incorporado swapbytes, que toma cualquier tipo de datos, intercambia el endianness y genera el resultado. En este caso, la entrada es un entero sin signo de 32 bits.



2

R , 86 bytes

Pensé que ya había una respuesta (o dos) en R para esta pregunta, pero debo haberme equivocado o tenían los mismos problemas que tuve con R sin hacer ints firmados. Ese problema eliminó cualquier cosa que pudiera haber ayudado. Intenté la conversión de 256 bases, pero terminó siendo demasiado larga, pero creo que todavía hay espacio para que alguien más inteligente que yo haga eso. Luego terminé con lo siguiente, que es una conversión de base 2 intercambiando el orden en una función 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)

Pruébalo en línea!

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

¡tenías razón sobre que la base 256 es más corta!
Giuseppe

@Giuseppe, te vas a poner el sombrero, ¿no?
MickyT

2

R , 41 bytes

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

Pruébalo en línea!

¡Verifique todos los casos de prueba!

Utiliza una conversión de base 256 como MickyT sugirió aquí . R no tiene enteros de 32 bits sin signo, ni tiene enteros de 64 bits. Esto nos impide usar operaciones bit a bit, pero este enfoque (y probablemente el de MickyT) probablemente sea aún más corto ya que los operadores bit a bit de R son bastante detallados.

Utiliza el número 4 de este consejo , teniendo en cuenta que nunca obtendremos un número tan grande como 256^4.

n%/%256^(0:3)%%256extrae los bytes y %*%, el producto de matriz, es el producto de punto en esta situación, con el 256^(3:0)efecto del orden inverso de bytes. %*%devolverá un 1x1 que matrixcontiene el valor invertido endian.


1

Conjunto CP-1610 , 6 DECLE = 8 bytes

Este código está destinado a ejecutarse en una Intellivision .

Un código de operación CP-1610 está codificado con un valor de 10 bits, conocido como 'DECLE'. Esta función tiene 6 DECLEs de largo, desde $ 480C y terminando en $ 4811.

El CP-1610 tiene registros de 16 bits, por lo que estamos utilizando dos de ellos (R0 y R1) para almacenar un 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

Volcado de ejecución

 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 qué es esto 7.5 bytes? Creo que debería ser de 8 bytes.
Erik the Outgolfer

@EriktheOutgolfer Bastante justo. Actualizado en consecuencia.
Arnauld el

@EriktheOutgolfer ¿Porque 60 bits equivalen a 7.5 bytes?
Jeppe Stig Nielsen

@JeppeStigNielsen Eso es cierto, pero un archivo nunca puede tener 7,5 bytes de longitud, se rellenará antes o después con 0s.
Erik the Outgolfer

@EriktheOutgolfer Técnicamente, esto realmente podría almacenarse dentro de una ROM de 10 bits. Aquí hay una hoja de especificaciones de ejemplo. (Hoy, estamos usando ROM de 16 bits para los juegos caseros de Intellivision, pero en el pasado, los chips de memoria eran tan caros que usar 10 bits era un verdadero ahorro de dinero.)
Arnauld

1

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

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

Pruébalo en línea!

+31 para using System;using System.Linq;

Esperaba usar en Array.Reverselínea, pero no fue así (vea la alternativa a continuación).

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

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

Pruébalo en línea!

+13 para using System;

Esta solución se preocupa por @JeppeStigNielsen; eliminando la restricción de tener todo en línea guardado 3 bytes.


Debido a que puede ahorrar using System.Linq;, aún puede ser más barato de 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))

Pruébalo en línea!

Sin golf:

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

Lenguaje de máquina ARM Linux, 8 bytes

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

Para probarlo usted mismo, compile y ejecute lo siguiente en 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 bytes

Solución:

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

Ejemplos:

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

Explicación:

No hay entradas sin signo, por lo que toma la entrada como un largo.

Convierta en matriz booleana (64 bits), cambie la forma, invierta, tome los primeros 8 bytes, vuelva a convertir a largo.

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

Prima:

Versión de 19 bytes en OK que puedes probar en línea.

2/,/8#|12 8#(64#2)\
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.