c++ - ¿Es posible diferenciar entre 0 y-0?
int zero (7)
Comencemos con la representación del complemento 0 en 2 (por supuesto, existen muchos otros sistemas y representaciones, aquí me refiero a este específico), suponiendo que 8 bits, cero es:
0000 0000
Ahora volteemos todos los bits y agreguemos 1 para obtener el complemento de 2:
1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000
tenemos
0000 0000
, y esa es la representación de -0 también.
Pero tenga en cuenta que en el complemento de 1, 0 con signo es 0000 0000, pero -0 es 1111 1111.
Sé que los valores enteros
0
y
-0
son esencialmente los mismos.
Pero me pregunto si es posible diferenciarlos.
Por ejemplo, ¿cómo sé si a una variable se le asignó
-0
?
bool IsNegative(int num)
{
// How ?
}
int num = -0;
int additinon = 5;
num += (IsNegative(num)) ? -addition : addition;
¿Se guarda el valor
-0
en la memoria exactamente igual que
0
?
Depende de la máquina a la que esté apuntando.
En una máquina que usa una
representación de complemento de 2
para enteros, no
hay diferencia a nivel de bit
entre
0
y
-0
(tienen la misma representación)
Si su máquina utiliza el complemento de uno , definitivamente podría
0000 0000 -> signed 0
1111 1111 -> signed −0
Obviamente estamos hablando de usar soporte nativo , los procesadores de la serie x86 tienen soporte nativo para la representación complementaria de dos números con signo. Usar otras representaciones es definitivamente posible, pero probablemente sería menos eficiente y requeriría más instrucciones.
(Como también señaló JerryCoffin: incluso si el complemento de uno se ha considerado principalmente por razones históricas, las representaciones de magnitud con signo siguen siendo bastante comunes y tienen una representación separada para cero negativo y positivo)
En la especificación del lenguaje C ++, no existe un int como negativo cero .
El único significado que tienen esas dos palabras es el operador unario
-
aplicado a
0
, así como
tres más cinco
es solo el operador binario
+
aplicado a
3
y
5
.
Si hubiera un cero negativo distinto , el complemento a dos (la representación más común de los tipos enteros) sería una representación insuficiente para las implementaciones de C ++, ya que no hay forma de representar dos formas de cero.
En contraste, los puntos flotantes (después de IEEE) tienen ceros positivos y negativos separados. Se pueden distinguir, por ejemplo, al dividir 1 entre ellos. El cero positivo produce infinito positivo; cero negativo produce infinito negativo.
Sin embargo, si hay diferentes representaciones de memoria de int 0 (o cualquier int, o cualquier otro valor de cualquier otro tipo), puede usar
memcmp
para descubrir que:
#include <string>
int main() {
int a = ...
int b = ...
if (memcmp(&a, &b, sizeof(int))) {
// a and b have different representations in memory
}
}
Por supuesto, si esto sucediera, fuera de las operaciones de memoria directa, los dos valores seguirían funcionando exactamente de la misma manera.
He decidido dejar esta respuesta ya que las implementaciones de C y C ++ generalmente están estrechamente relacionadas, pero de hecho no difiere del estándar C como pensaba. El punto sigue siendo que el estándar C ++ no especifica lo que sucede para casos como estos. También es relevante que las representaciones que no son de dos complementos son extremadamente raras en el mundo real, y que incluso donde existen a menudo ocultan la diferencia en muchos casos en lugar de exponerla como algo que alguien podría esperar descubrir fácilmente.
El comportamiento de los ceros negativos en las representaciones de enteros en los que existen no está tan rigurosamente definido en el estándar C ++ como en el estándar C. Sin embargo, sí cita el estándar C (ISO / IEC 9899: 1999) como referencia normativa en el nivel superior [1.2].
En el estándar C [6.2.6.2], un cero negativo solo puede ser el resultado de operaciones bit a bit u operaciones en las que ya existe un cero negativo (por ejemplo, multiplicando o dividiendo un cero negativo por un valor, o agregando un cero negativo a cero): la aplicación del operador menos unario a un valor de un cero normal, como en su ejemplo, por lo tanto, garantiza un cero normal.
Incluso en los casos que pueden generar un cero negativo, no hay garantía de que lo harán, incluso en un sistema que admite cero negativo:
No se especifica si estos casos realmente generan un cero negativo o un cero normal, y si un cero negativo se convierte en un cero normal cuando se almacena en un objeto.
Por lo tanto, podemos concluir: no, no hay una forma confiable de detectar este caso. Incluso si no fuera por el hecho de que las representaciones que no son dos complementos son muy poco comunes en los sistemas informáticos modernos.
El estándar C ++, por su parte, no menciona el término "cero negativo", y tiene muy poca discusión sobre los detalles de la magnitud firmada y las representaciones del complemento de uno, excepto para observar [3.9.1 párrafo 7] que están permitidos.
Para simplificar, me resultó más fácil visualizarlo.
El tipo int (_32) se almacena con 32 bits . 32 bits significa 2 ^ 32 = 4294967296 valores únicos . Así:
el rango de datos int sin signo es de 0 a 4,294,967,295
En caso de valores negativos, depende de cómo se almacenan. En caso
- Complemento de dos –2,147,483,648 a 2,147,483,647
- Complemento de uno –2,147,483,647 a 2,147,483,647
En el caso del complemento , existe el valor -0.
Para un
int
(en la representación casi universal del "complemento de 2") las representaciones de
0
y
-0
son las mismas.
(Pueden ser diferentes para otras representaciones de números, p. Ej., Coma flotante IEEE 754).
Si su máquina tiene representaciones distintas para
-0
y
+0
,
memcmp
podrá distinguirlas.
Si los bits de relleno están presentes, en realidad también puede haber múltiples representaciones para valores distintos de cero.