2011-01-19 17 views
10

Tengo dos enteros que necesito pasar a través de un entero y luego recuperar los valores de dos enteros.Pasar dos enteros como un entero

Estoy pensando en utilizar operadores lógicos (AND, OR, XOR, etc.).

+1

¿qué quiere decir pasar a través de? ¿Puedes dar un mejor ejemplo? –

+3

¿Cuantos bits son los dos originales enteros? –

+0

¿Qué lenguaje de programación está utilizando? y cuál es el valor máximo de cada uno de los 2 enteros que desea pasar. –

Respuesta

1

Dos enteros no caben en un entero, o al menos no puede recuperar los dos originales.
Pero de todos modos, si los dos enteros originales se limita a un número seguro de bits que puede (en preudocode): primer entero OR con (segundo entero SHIFTLEFT (nOfBits))

para volver los dos enteros enmascare el entero fusionado con un número que es binario representado por nOfBitsOne y obtiene el primer entero, luego ShiftRight por nOfBits del entero fusionado, y tiene el segundo.

+0

Dos enteros realmente pueden "caber" en un entero y volverse a convertir. Esto se debe a que la cardinalidad del conjunto de pares enteros ordenados es igual a la cardinalidad de los enteros. Es decir, hay tantos enteros como pares enteros ordenados. Puede lograr esto con la máscara de bits, si sabe cuántos bits tiene, como señalaron los otros carteles. También puede usar algo como [la función de emparejamiento de Cantor] (https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function) – ubadub

3

Bueno .. @Felice es correcto, pero si ambos encajan en 16 bits hay una manera:

output_int = (first_int << 16) | second_int 
          ^
          means 'or' 

al paquete de ellos, y

first_int = output_int & 0xffff 
second_int = (output int >> 16) & 0xffff 
           ^
          means 'and' 

para extraerlos.

+0

Me gusta esta solución, pero no puedo otorgar los datos –

+0

@Mohammed: Usar un int largo puede ayudar tú. Cambie por 32 bits y luego – BlackBear

0

Puede almacenar 2 enteros de 16 bits dentro de un entero de 32 bits. Primero uno i 16 primeros bits y el segundo en los últimos 16 bits. Para recuperar y componer el valor, usa shift-operators.

10

Usando el lenguaje de programación C, que se podía hacer el siguiente, suponiendo que los dos números enteros están a menos de 65535.

void take2IntegersAsOne(int x) 
{ 
    // int1 is stored in the bottom half of x, so take just that part. 
    int int1 = x & 0xFFFF; 

    // int2 is stored in the top half of x, so slide that part of the number 
    // into the bottom half, and take just that part. 
    int int2 = (x >> 16) & 0xFFFF 

    // use int1 and int2 here. They must both be less than 0xFFFF or 65535 in decimal 

} 


void pass2() 
{ 
    int int1 = 345; 
    int int2 = 2342; 
    take2Integers(int1 | (int2 << 16)); 
} 

Esto se basa en el hecho de que en C un número entero se almacena en 4 bytes. Entonces, el ejemplo usa los primeros dos bytes para almacenar uno de los enteros, y los siguientes dos bytes para el segundo. Sin embargo, esto impone el límite de que cada uno de los enteros debe tener un valor lo suficientemente pequeño para que encajen en solo 2 bytes.

Los operadores de cambio < < y >> se utilizan para deslizar los bits de un entero hacia arriba y hacia abajo. Cambiando por 16, mueve los bits por dos bytes (ya que hay 8 bits por byte).

Usando 0xFFFF representa el patrón de bits donde todos los bits en los dos bytes inferiores del número son 1s, ANDing (con el operador &) hace que todos los bits que no están en estos dos bytes inferiores se apaguen (de vuelta a cero). Esto se puede usar para eliminar cualquier parte del "otro entero" de la que está extrayendo actualmente.

4

Esta pregunta tiene dos partes. En primer lugar, ¿cómo se combinan los bits de dos enteros de 32 bits en un entero largo de 64 bits?

Como han indicado otros, supongamos que tengo una función que toma una coordenada X e Y, y devuelve un signo largo que representa el valor lineal de ese Punto. Tiendo a llamar a esta linealización de datos 2D:

public long asLong(int x, int y) { 
    return (((long)x) << 32) | y; 
} 

public int getX(long location) { 
    return (int)((location >> 32) & 0xFFFFFFFF); 
} 

public int getY(long location) { 
    return (int)(location & 0xFFFFFFFF); 
} 

Perdóname si soy paranoico sobre orden de las operaciones, a veces otras operaciones son más golosa < <, haciendo que las cosas cambien más de lo que deberían.

¿Por qué funciona esto? ¿Cuándo podría fallar? Es conveniente que los números enteros tiendan a tener exactamente la mitad del tamaño de longints. Lo que estamos haciendo es lanzar x a un largo, desplazándolo hacia la izquierda hasta que se sienta completamente a la izquierda de y, y luego hacer una operación de unión (OR) para combinar los bits de ambos.

Vamos a suponer que son números de 4 bits se combinan en un número de 8 bits:

x = 14  :  1110 
y = 5  :  0101 

x = x << 4 : 1110 0000 

p = x | y : 1110 0000 
      OR  0101 
      --------- 
      1110 0101 

Mientras tanto, a la inversa:

p = 229 : 1110 0101 
x = p >> 4 : 1111 1110 //depending on your language and data type, sign extension 
         //can cause the bits to smear on the left side as they're 
         //shifted, as shown here. Doesn't happen in unsigned types 
x = x & 0xF: 
      1111 1110 
     AND 0000 1111 
     ------------- 
      0000 1110 //AND selects only the bits we have in common 

y = p & 0xF: 
      1110 0101 
     AND 0000 1111 
     ------------- 
      0000 0101 //AND strikes again 

Este tipo de enfoque llegó a existir un largo Hace tiempo, en entornos que necesitaban exprimir cada bit de su espacio de almacenamiento o transmisión. Si no estás en un sistema embebido o embalaje inmediatamente estos datos para la transmisión a través de una red, el sentido práctico de todo este procedimiento empieza a descomponerse muy rápidamente:

  • Es demasiado trabajo sólo para boxeo un valor de retorno que casi siempre debe ser inmediatamente desempaquetado y leído por la persona que llama. Eso es como cavar un hoyo y luego llenarlo.
  • Reduce enormemente la legibilidad del código. "¿Qué tipo se devuelve?" Uh ... un int .. y otro int ... en mucho tiempo.
  • Puede introducir errores difíciles de rastrear en la línea. Por ejemplo, si usa tipos sin firmar e ignora la extensión del signo, más adelante migrará a una plataforma que hace que esos tipos sean complementarios. Si guardas el longint largo e intentas leerlo más tarde en otra parte de tu código, es posible que aciertes un error "uno a uno" en el cambio de bits y pasas una hora depurando tu función solo para descubrir que es el parámetro que está mal.

Si es tan malo, ¿cuáles son las alternativas?

Es por esto que la gente le pregunta acerca de su idioma. Lo ideal sería que, si estás en algo así como C o C++, que sería mejor decir

struct Point { int x; int y; }; 

public Point getPosition() { 
    struct Point result = { 14,5 }; 
    return result; 
} 

De lo contrario, en HLL como Java, es posible terminar con una clase interna para lograr la misma funcionalidad:

public class Example { 
    public class Point { 
     public int x; 
     public int y; 
     public Point(int x, int y) { this.x=x; this.y=y; } 
    } 

    public Point getPosition() { 
     return new Point(14,5); 
    } 
} 

En este caso, getPosition devuelve un Example.Point - si sigue utilizando el Point frecuentemente, promuévelo a una clase completa propia. De hecho, java.awt ya tiene varias clases Point, incluido Point and Point.Float

Finalmente, muchos lenguajes modernos ahora tienen azúcar sintáctico para encapsular múltiples valores en tuplas o devolver directamente múltiples valores de una función. Esto es como un último recurso. En mi experiencia, cada vez que pretendes que los datos no son lo que es, terminas con problemas en el futuro. Pero si su método absolutamente debe devolver dos números que realmente no son parte de los mismos datos en absoluto, las tuplas o matrices son el camino a seguir.

La referencia para el C++ tupla stdlib se puede encontrar en http://www.cplusplus.com/reference/std/tuple/

Cuestiones relacionadas