Cuando se lee el título de la pregunta, asignar 2^31 a una variable entera de 32 bits con signo y sin signo da un resultado inesperado.Resultado extraño después de asignar 2^31 a una variable entera de 32 bits con signo y sin signo
Aquí es el programa corto (en C++
), el cual hice para ver lo que está pasando:
#include <cstdio>
using namespace std;
int main()
{
unsigned long long n = 1<<31;
long long n2 = 1<<31; // this works as expected
printf("%llu\n",n);
printf("%lld\n",n2);
printf("size of ULL: %d, size of LL: %d\n", sizeof(unsigned long long), sizeof(long long));
return 0;
}
Aquí está la salida:
MyPC/# c++ test.cpp -o test
MyPC/# ./test
18446744071562067968 <- Should be 2^31 right?
-2147483648 <- This is correct (-2^31 because of the sign bit)
size of ULL: 8, size of LL: 8
Luego añade otra función p()
, a ella :
void p()
{
unsigned long long n = 1<<32; // since n is 8 bytes, this should be legal for any integer from 32 to 63
printf("%llu\n",n);
}
En la compilación y ejecución, esto es lo que confunde d mí aún más:
MyPC/# c++ test.cpp -o test
test.cpp: In function ‘void p()’:
test.cpp:6:28: warning: left shift count >= width of type [enabled by default]
MyPC/# ./test
0
MyPC/
¿Por qué el compilador quejarse valor de desplazamiento a la izquierda es demasiado grande? sizeof(unsigned long long
) devuelve 8, ¿no significa eso que 2^63-1 es el valor máximo para ese tipo de datos?
Se me ocurrió que tal vez n * 2 y n < < 1, no siempre se comportan de la misma manera, así que probamos este:
void s()
{
unsigned long long n = 1;
for(int a=0;a<63;a++) n = n*2;
printf("%llu\n",n);
}
Esto da el valor correcto de 2^63 como la salida que es 9223372036854775808
(lo verifiqué usando python). Pero, ¿qué hay de malo en hacer una mierda de izquierda?
Un desplazamiento aritmético izquierda de n es equivalente a multiplicar por 2 n (siempre que el valor no se desborde)
- Wikipedia
El valor no está desbordando , solo aparecerá un signo menos ya que el valor es 2^63 (todos los bits están configurados).
Todavía no puedo entender qué está pasando con el turno de la izquierda, ¿alguien puede explicar esto?
PS: Este programa se ejecuta en una casa de moneda de 32 bits Linux sistema en funcionamiento (si eso ayuda)
Esto debería ser 'unsigned long long n = 1ULL << 31;' – kirilloid
dios! ¿Fue así de fácil? ¿Por qué no lo pensé? de todos modos, sí 1ULL << 31 funciona. ¡así que gracias! – Rushil