¿Es posible diferenciar entre 0 y -0?

94

Sé que los valores enteros 0y -0son esencialmente los mismos. Pero me pregunto si es posible diferenciarlos.

Por ejemplo, ¿cómo sé si se asignó una variable -0?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

¿El valor -0guardado en la memoria es exactamente igual que 0?

Filip Minx
fuente
9
Para enteros, no hay diferencia.
Maroun
14
Esto depende de la implementación, pero para las implementaciones donde intse representa en complemento a 2 (con mucho, el más común) 0y -0tienen representaciones bit a bit idénticas.
Mankarse
11
En una máquina de complemento a 2 no hay diferencia a nivel de bit.
Marco A.
17
@VirtualSnake: ¿Qué significa "en binario"? De hecho, existen codificaciones binarias para las que se distingue entre -0 y 0. Signo y magnitud, por ejemplo.
Benjamin Lindley
8
@VirtualSnake Así es, estamos hablando int. Consulte la codificación del complemento de unos .
CiaPan

Respuestas:

112

Depende de la máquina a la que apuntes.

En una máquina que usa una representación de complemento a 2 para enteros, no hay diferencia a nivel de bit entre 0y -0(tienen la misma representación)

Si su máquina usara el complemento de uno , definitivamente podría

0000 0000   -> signed01111 1111   -> signed   0

Obviamente, estamos hablando de usar soporte nativo , los procesadores de la serie x86 tienen soporte nativo para la representación del complemento a dos de números con signo. Definitivamente es posible usar otras representaciones, 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)

Marco A.
fuente
6
@TobiMcNamobi: No es lo suficientemente probable como para preocuparse. Me sorprendería que alguien se haya molestado alguna vez en portar un compilador de C ++ para producir una salida para tal máquina.
Benjamin Lindley
1
Estoy de acuerdo con Benjamin, históricamente ha habido máquinas que lo utilizan, pero hoy en día no conozco máquinas de producción que lo utilicen. Sin embargo, siempre es bueno saberlo y tenerlo en cuenta.
Marco A.
4
El complemento de @TobiMcNamobi todavía está en uso en el sistema UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv
2
Nunca he analizado los requisitos de complemento de uno: ¿el estándar realmente garantiza eso 0y -0son diferentes ? Honestamente, hubiera esperado que se comportara más como permitir representaciones de dos bits del mismo valor, y su programa puede usar la que le parezca.
8
@Hurkly: no, aunque exista una representación de cero negativo, el estándar no garantiza que la asignación o inicialización usando la expresión -0, es decir, el resultado de aplicar el -operador unario a la constante entera 0, sea una representación de cero negativo. Independientemente de la representación, el estándar nunca dice 0y -0son valores matemáticamente diferentes, solo que puede haber un patrón de bits negativo-cero. Si lo hay, todavía representa el mismo valor numérico, 0.
Steve Jessop
14

Para una int(en la representación casi universal de "complemento a 2") las representaciones de 0y -0son lo mismo. (Pueden ser diferentes para otras representaciones numéricas, por ejemplo, punto flotante IEEE 754).

RichieHindle
fuente
9
>> Suponiendo una representación en complemento a 2
Marco A.
12

Comencemos por representar 0 en el complemento de 2 (por supuesto que existen muchos otros sistemas y representaciones, aquí me refiero a este específico), asumiendo que el cero de 8 bits 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.

Maroun
fuente
1
¿Puedo saber por qué los votos negativos para mejorar mi respuesta, por favor?
Maroun
1
Si bien la mayoría de las otras respuestas son técnicamente correctas, su respuesta es práctica y proporciona una implementación. Bueno.
umlcat
9

Decidí 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 pensé. El punto es que el estándar C ++ no especifica lo que sucede en casos como estos. También es relevante que las representaciones que no son de complemento a dos 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 enteras en las que existen no está tan rigurosamente definido en el estándar C ++ como lo está en el estándar C. Sin embargo, sí cita la norma 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 o de operaciones en las que ya está presente un cero negativo (por ejemplo, multiplicar o dividir un cero negativo por un valor, o agregar un cero negativo a cero): la aplicación del operador menos unario a un valor de un cero normal, como en su ejemplo, está garantizado para dar como resultado 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 generan realmente 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 tanto, podemos concluir: no, no existe una forma fiable de detectar este caso. Incluso si no fuera por el hecho de que las representaciones de complemento no a dos 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 con signo y las representaciones de complemento a uno, excepto para notar [3.9.1 párrafo 7] que están permitidos.

Aleatorio832
fuente
En general no, el hecho de que algo sea verdadero / requerido en C no significa necesariamente que sea cierto / requerido en C ++. El hecho de que C sea una referencia normativa significa que C ++ se refiere al estándar C para varias cosas (principalmente el contenido de los encabezados estándar), pero la definición de tipos enteros no es una de esas cosas. Sin embargo, la ausencia de una forma garantizada de producir un cero negativo significa que lo que concluye sigue siendo cierto, no hay una forma segura de generar uno usando aritmética incluso si la representación existe.
Steve Jessop
Entonces, ¿por qué el estándar C ++ entra en muchos menos detalles en cosas como esta?
Random832
1
Gusto personal, creo, si el número de personas que votan por el estándar C ++ puede considerarse "personal" :-) Si fuera a ceder al estándar C para las definiciones, entonces podría hacer un buen trabajo. y no contienen detalles, como ocurre en algunos otros casos.
Steve Jessop
¿"C ++ es un lenguaje de programación de propósito general basado en el lenguaje de programación C como se describe en ISO / IEC 9899: 1999 Lenguajes de programación - C (en adelante referido como el estándar C)". [1.1 párrafo 2] ¿tiene algún significado normativo? Pensé que eso estaba destinado a incorporar generalmente el estándar C para cualquier cosa que no esté anulada específicamente por el estándar C ++.
Random832
@ Sólo una nota histórica de Random832 No. (hay, por ejemplo, ninguna _Boolo _Complexo inicializadores designados o literales compuestos en C ++). El estándar C ++ sabe cómo incorporar el estándar C cuando quiere, por ejemplo, [basic.fundamental] / p3: "Los tipos enteros con signo y sin signo deben satisfacer las restricciones dadas en el estándar C, sección 5.2.4.2.1".
TC
8

Si su máquina tiene representaciones distintas para -0y +0, memcmppodrá distinguirlas.

Si hay bits de relleno, es posible que también haya varias representaciones para valores distintos de cero.

Ben Voigt
fuente
5

En la especificación del lenguaje C ++, no existe un int como cero negativo .

El único significado que tienen esas dos palabras es el operador unario -aplicado 0, al igual que tres más cinco es solo el operador binario +aplicado a 3y 5.

Si hubiera un cero negativo distinto , el complemento a dos (la representación más común de tipos enteros) sería una representación insuficiente para las implementaciones de C ++, ya que no hay forma de representar dos formas de cero.


Por el contrario, los puntos flotantes (siguiendo IEEE) tienen ceros positivos y negativos separados. Se pueden distinguir, por ejemplo, al dividir 1 por ellos. El cero positivo produce infinito positivo; cero negativo produce infinito negativo.


Sin embargo, si hay diferentes representaciones de memoria del int 0 (o cualquier int, o cualquier otro valor de cualquier otro tipo), puede usar memcmppara 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.

Paul Draper
fuente
3
En realidad, el hecho de que el lenguaje no exija su existencia no significa que exija su ausencia. Sugerencia: no exige ninguno.
Deduplicador
2
@Deduplicator, algo así. Por "en el lenguaje C ++", quiero decir, "en la especificación del lenguaje C ++ ". Dado que tampoco hay mención de froobinators en la especificación, podría decir "C ++ no tiene froobinators" sin demasiada ambigüedad. Pensé que estaba claro, pero lo mejoraré.
Paul Draper
1
La especificación del idioma tampoco menciona a los unicornios.
ypercubeᵀᴹ
2

Para simplificar, lo encontré más fácil de visualizar.

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 almacenen. En caso

En el caso del complemento a uno, existe el valor -0.

Margus
fuente
2
No he votado negativamente, pero las plataformas para las que intno se almacena en 32 bits son más populares que las plataformas con complemento de uno en la actualidad.
Maciej Piechotka