Experimento-Laboratorio de datos de "comprensión profunda de los sistemas informáticos" (CSAPP)

Este artículo es un experimento complementario del segundo capítulo de CSAPP. Utiliza operadores limitados para realizar la representación a nivel de bits de números positivos, números negativos y números de punto flotante. Al completar estas 13 funciones, podemos comprender mejor la codificación de datos en la computadora.

Listo para trabajar

  Primero, vaya al sitio web oficial de Asignaciones de laboratorio para obtener los archivos relacionados con el experimento (también puede agregar mi QQ para obtener videos de enseñanza, PPT, etc.). El archivo README de cada archivo de experimento detalla cómo modificar el programa, compilar el programa, etc. Se recomienda leerlo detenidamente y dejar un mensaje si no lo entiende, y responderá a tiempo después de verlo.

  Mi entorno de compilación: Ubuntu 16.04, gcc 5.4.0.

  Se informará del siguiente error al compilar.

imagen-20201026150615228

  Ejecute el siguiente comando para instalar el paquete de 64 bits.

sudo apt-get purge libc6-dev
sudo apt-get install libc6-dev
sudo apt-get install libc6-dev-i386

  Vuelva a compilar, no se informa ningún error, es normal.

imagen-20201026150733398

tema

bitXor

Ideas

  La ley de De Morgan también se llama inversión.

Código

/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */
int bitXor(int x, int y) {
    
    
 return ~(x & y) & ~(~x & ~y);
}

tmin

Ideas

  El valor mínimo del complemento 0x80000000

Código

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
    
    
  return 1<<31;
}

isTmax

Ideas

  Determina si es el valor máximo del complemento. El valor máximo del complemento de 32 bits es 0x7fffffff, que se aplica XOR con él,

Código

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 2
 */
int isTmax(int x) {
    
    
  return !(x^0x7fffffff);
}

allOddBits

Ideas

  Este problema es relativamente simple y se resuelve mediante enmascaramiento. Primero, debemos construir la máscara, usar el operador de desplazamiento para construir una máscara numérica con todos los 1 en los dígitos impares, luego obtener los dígitos impares del valor de entrada x, borrar los otros bits (máscara & x) y luego realizar una operación OR exclusiva con la máscara. Es 0 y luego devuelve la negación lógica de su valor.

Código

/* 方法一
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
    
    
  int mask = 0xAA+(0xAA<<8);
  mask=mask+(mask<<16);
  return !((mask&x)^mask);
}
/* 方法二
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
    
    
  return !(~x&0xaaaaaaaa);
}

negar

Ideas

  El complemento es en realidad un grupo abeliano, para x, -x es su complemento, por lo que -x se puede obtener sumando 1 ax

Código

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
    
    
  return ~x+1;
}

isAsciiDigit

Ideas

  La diferencia entre x y '0' y '9' respectivamente, y luego juzgue si el bit de signo es 0 o 1 según el resultado de la diferencia

Código

/*

 * isAsciiDigit -return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')

 *   Example: isAsciiDigit(0x35) = 1.

 *            isAsciiDigit(0x3a) = 0.

 *            isAsciiDigit(0x05) = 0.

 *   Legal ops: ! ~ & ^ | + << >>

 *   Max ops: 15

 *   Rating: 3

 */

int isAsciiDigit(int x) {
    
    

  return(!((x+~48+1)>>31))&!!((x+~58+1)>>31);

}

condicional

Ideas

  Convierta x a todos 0 o todos 1. Observe aquí que el complemento de 0 es 0 y el bit representa todo 0. El complemento de 1 es -1 y el bit representa todo 1. Cuando x se convierte en todo 0 y todo 1, entonces (x & y) o (~ x & z), uno de ellos debe establecerse. Lo que se devuelve es el valor de yoz

Código

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(3,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
    
    
  x = !!x;
  x = ~x+1;//求补码
  return (x&y)|(~x&z);
}

isLessOrEqual

Ideas

  Comparar el tamaño de dos números mediante la operación de bits no es más que dos casos: uno es que el signo es diferente y el número positivo es más grande, y el otro es que el signo es el mismo para ver el signo de diferencia.

Código

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
    
    
  int negX=~x+1;//-x
  int addX=negX+y;//y-x
  int checkSign = addX>>31&1; //y-x的符号
  int leftBit = 1<<31;//最大位为1的32位有符号数
  int xLeft = x&leftBit;//x的符号
  int yLeft = y&leftBit;//y的符号
  int bitXor = xLeft ^ yLeft;//x和y符号相同标志位,相同为0不同为1
  bitXor = (bitXor>>31)&1;//符号相同标志位格式化为0或1
  return ((!bitXor)&(!checkSign))|(bitXor&(xLeft>>31));//返回1有两种情况:符号相同标志位为0(相同)位与 y-x 的符号为0(y-x>=0)结果为1;符号相同标志位为1(不同)位与x的符号位为1(x<0)
}

LogicNeg

Ideas

  La negación lógica significa que un valor distinto de cero es 1 y un valor distinto de cero es cero. Utilizando la naturaleza de su complemento (invertido más uno), excepto por 0 y el número más pequeño (el bit de signo es 1, el resto es 0 ), los otros números están en relaciones opuestas (el bit de signo es 1). El complemento de 0 y el número más pequeño es él mismo, pero el bit de signo de 0 y su complemento es 0, y el número más pequeño es 1. Use esto para obtener una solución.

Código

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */

int logicalNeg(int x) {
    
    
  return ((x|(~x+1))>>31)+1;
}

howManyBits

Ideas

  El complemento de un número positivo: el 1 más alto de un número positivo es el número n, más el bit de signo, el resultado es n + 1.

  El complemento de un número negativo: conviértalo en un número positivo, como se indicó anteriormente.

/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */
int howManyBits(int x) {
    
    
  int b16,b8,b4,b2,b1,b0;
  int mask = x >> 31;
  x = (mask & ~x) | (~mask & x); //如果为正数,保持不变;如果为负数,按位取反

  //step1:判断高16为是否有1
  b16 = !!(x >> 16) << 4; //如果高16为有1,则b16 = 16,否则为0
  x >>= b16; //如果高16为有1,x右移16位舍弃低16位,在新的低16位继续查找;否则保持不变
  //step2:判断高8位是否有1
  b8 = !!(x >> 8) << 3;
  x >>= b8;
  //step3:高4位
  b4 = !!(x >> 4) << 2;
  x >>= b4;
  //step4:高2位
  b2 = !!(x >> 2) << 1;
  x >>= b2;
  //step5:高1位
  b1 = !!(x >> 1);
  x >>= b1;
  //step6:低1位
  b0 = x;

  return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}

floatScale2

Ideas

Formato de coma flotante estándar

Clasificación de valores de coma flotante de precisión simple

  Consulte la figura anterior para comprender. Si no entiende, vuelva atrás y observe el formato de número de punto flotante estándar de IEEE "Comprensión profunda de los sistemas informáticos" (CSAPP), notas de lectura: Capítulo 2 Representación y procesamiento de información

  Principalmente según el valor de entrada, se puede dividir en tres situaciones:

  1. Ingrese uf como infinito y NaN, y regrese uf directamente

  2. Si uf es 0 o infinitesimal, devuelve 2 * uf + signo

  3. Si exp + 1 == 255, devuelve infinito; de lo contrario, devuelve exp + 1. (Exp es la parte entera de la codificación numérica de punto flotante, exp + 1 es equivalente a uf * 2).

Código

/* 
 * floatScale2 - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned floatScale2(unsigned uf) {
    
    
  int exp = (uf&0x7f800000)>>23;//取出exp部分
  int sign = uf&(1<<31);//取出符号位
  if(exp==0) return uf<<1|sign;//情况2
  if(exp==255) return uf;//情况1
  exp++;
  if(exp==255) return 0x7f800000|sign;//情况3
  return (exp<<23)|(uf&0x807fffff);
}

floatFloat2Int

Ideas

imagen-20201027203703175

  1. Desnormalización, lo que significa que el número está muy cerca de 0, que es 0 después de convertirse en un valor int.

  2. Normalización, la distribución de números es cada vez más escasa desde cerca de 0 hasta el infinito. Cuando f no excede el rango del tipo int, se convierte a int; cuando excede el rango del tipo int, devuelve 0x80000000u

  3. Especial, devuelve 0x8000000u

  Cuando el flotante normalizado se convierte en un entero int,

  Si E> = 31, el punto decimal se desplaza 31 bits hacia la derecha. En este momento, el 1 implícito y el frac ocupan 32 bits y se necesita un bit de signo, que excede el rango del tipo int.

  Si E <0, después de que el punto decimal se desplaza 1 lugar hacia la izquierda, se convierte en 0.1frac, y después de la conversión a int, se convierte en 0

  Si 0 <E <23, después de que el punto decimal se desplaza hacia la izquierda por E, algunos dígitos en frac deben descartarse. En este momento, cambie directamente frac a la derecha en 23-E dígitos y borre la parte decimal

  Si 23 <= E <31, en este momento, después de que el punto decimal se desplaza hacia la derecha, la fracción se desplaza hacia la izquierda del punto decimal y la fracción se desplaza hacia la izquierda por E-23, y se agregan ceros al final.

Código

/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
int floatFloat2Int(unsigned uf) {
    
    
  int sign = (uf >> 31) & 1;
  int exp = (uf >> 23) & 0xff;
  int frac = uf & 0x7fffff;

  int E = exp - 127;

  if (E < 0) //小数
  {
    
    
    return 0;
  }
  else if (E >= 31) // 超出int范围
  {
    
    
    return 0x80000000u;
  }
  else
  {
    
    
    frac = frac | (1 << 23);  //加上隐含的1

    if (E < 23)     //舍去部分小数
    {
    
    
      frac >>= (23 - E);
    }
    else        //不需要舍去小数
    {
    
    
      frac <<= (E - 23);
    }

    if (sign)
      return -frac;
    else
      return frac;
  }
}

floatPower2

Ideas

Según la fórmula de evaluación numérica de punto flotante: V = (- 1) s × M × 2 EV = {(-1) ^ s} \ times M \ times {2 ^ E}V=( - 1 )s×METRO×2mi

1. Estandarización

令 M = 1 (frac = 0) , xEexp-Bias , exp = x + Bias

2. Desnormalización

exp = 0, establece un bit en frac en 1, haciendo x más pequeño.

Exp frac METRO maxE Mía
Desnormalización 0 0 * 10 * 0.frac -127 -148
Normalización Distinto de cero 0 1.0 127 -126

Análisis de condiciones de contorno

1. Desormalización

  • Cuando frac = 100 0000 0000 0000 0000 0000, M = 0.1b = 0.5, E = 1- Sesgo = -126, en este momento v = 0.5 * 2.0 ^ -126 = 2.0 ^ -127
  • Cuando frac = 000 0000 0000 0000 0000 0001, M = 0.000 0000 0000 0000 0000 0001 = 2.0 ^ -22, E = -126, en este momento v = 2.0 ^ -22 * 2 ^ -126 = 2.0 ^ -148

2. Estandarización

  • Cuando exp = 0xFF, E = exp-Bias = 127
  • Cuando exp = 1, E = exp-Bias = -126

Código

unsigned floatPower2(int x) {
    
    
  if (x > 127) //too large, return +INF
  {
    
    
    return (0xFF << 23);
  }
  else if (x < -148) //too small, return 0
  {
    
    
    return 0;
  }
  else if (x >= -126) //norm,计算exp
  {
    
    
    int exp = x + 127;
    return (exp << 23);
  }
  else //denorm,令frac中某一位为1
  {
    
    
    int t = 148 + x;
    return (1 << t);
  }
}

Resultados de la prueba

imagen-20201028110707561

para resumir

  Los siguientes temas siguen consumiendo mucho cerebro y no entiendo los temas, la razón principal es que el concepto no se comprende bien. Más tarde, volví a leer el libro, entendí los conceptos básicos, leí las soluciones de otras personas y el problema se fue aclarando gradualmente. El código del proceso de resolución de problemas también se registra y puede haber nuevas soluciones después de volver al segundo cepillo después de un tiempo. Todavía hay algunos experimentos esperándome más tarde, tómate tu tiempo. Bienvenido a seguir mi blog para recibir notificaciones de actualizaciones oportunas.

  Finalmente, compartiré una broma que vi en el PPT, contando ovejas ~ Jaja ~ ¡Hágalo
Captura de pantalla de QQ 20201028162245
  un hábito, como primero y luego lea! Si cree que la escritura es buena, bienvenido a prestar atención, como, marcador, ¡gracias!

Declaración de derechos de autor: Este artículo es el artículo original del blogger y sigue el acuerdo de derechos de autor CC 4.0 BY-SA. Adjunte el enlace de la fuente original y esta declaración para reimprimir.
Enlace a este artículo: https://blog.csdn.net/qq_16933601/article/details/109328995

Supongo que te gusta

Origin blog.csdn.net/qq_16933601/article/details/109328995
Recomendado
Clasificación