sirve que para long data and c++ c++11 integer standards ones-complement

que - long long c++ range



Comportamiento de cero negativo en la arquitectura de un complemento? (3)

Basado en mi interpretación del estándar:

El estándar de C ++ en §3.9.1 / p3 Tipos fundamentales [basic.fundamental] realmente arroja la pelota en el estándar C:

Los tipos enteros con signo y sin signo cumplirán las restricciones dadas en el estándar C, sección 5.2.4.2.1.

Ahora, si vamos a la sección 5.2.4.2.1 de ISO / IEC 9899: 2011, da como referencia directa a §6.2.6.2 / p2 Tipos enteros ( Mina Emphasis ):

Si el bit de signo es cero, no afectará el valor resultante. Si el bit de signo es uno, el valor se modificará de una de las siguientes maneras:

  • el valor correspondiente con el bit de signo 0 es negado (signo y magnitud);

  • el bit de signo tiene el valor - (2 ^ M) (complemento de dos);

  • el bit de signo tiene el valor - (2 ^ M - 1) (complemento de unos).

Cuál de estos aplica es definido por implementación , como si el valor con el bit de signo 1 y todos los bits de valor cero (para los dos primeros) o con el bit de signo y todos los bits de valor 1 (para el complemento de uno) es una representación trampa o un valor normal En el caso de signo y magnitud y el complemento de uno, si esta representación es un valor normal, se llama cero negativo.

En consecuencia, la existencia de cero negativo es la implementación definida.

Si avanzamos en el párrafo 3:

Si la implementación admite ceros negativos, se generarán solo por:

  • los operadores &, |, ^, ~, << y >> con operandos que producen dicho valor;

  • los operadores +, -, *, / y% donde un operando es un cero negativo y el resultado es cero;

  • operadores de asignación compuesta basados ​​en los casos anteriores.

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.

En consecuencia, no se especifica si los casos relacionados que se muestran van a generar un cero negativo en absoluto.

Ahora procediendo en el párrafo 4:

Si la implementación no admite ceros negativos, el comportamiento de los operadores &, |, ^, ~, << y >> con operandos que producirían dicho valor no está definido.

En consecuencia, si las operaciones relacionadas dan como resultado un comportamiento indefinido, depende de si la implementación admite ceros negativos.

Considere el siguiente código en la arquitectura de un complemento:

int zero = 0; int negzero = -0; std::cout<<(negzero < zero)<<std::endl; std::cout<<(negzero <= zero)<<std::endl; std::cout<<(negzero == zero)<<std::endl; std::cout<<(~negzero)<<(~zero)<<std::endl; std::cout<<(1 << negzero)<<std::endl; std::cout<<(1 >> negzero)<<std::endl;

  • ¿Qué salida produciría el código?
  • ¿Qué líneas están definidas por el estándar, de qué líneas depende la implementación y qué líneas son comportamientos indefinidos?

En primer lugar, su primera premisa es incorrecta:

int negzero = -0;

debería producir un cero normal en cualquier arquitectura conforme.

Las referencias para eso se dieron en la respuesta de @ 101010:

3.9.1 Tipos fundamentales [basic.fundamental] §3:

... Los tipos enteros con signo y sin signo deberán cumplir las restricciones dadas en el estándar C, sección 5.2.4.2.1.

Más tarde en referencia C: 5.2.4.2.1 Tamaños de tipos enteros

... Referencias futuras: representaciones de tipos (6.2.6)

y (aún C): 6.2.6 Representaciones de tipos / 6.2.6.2 Tipos enteros § 3

Si la implementación admite ceros negativos, se generarán solo por:

  • los operadores &, |, ^, ~, << y >> con argumentos que producen dicho valor;

  • los operadores +, -, *, / y% donde un argumento es un cero negativo y el resultado es cero;

  • operadores de asignación compuesta basados ​​en los casos anteriores.

Entonces, negzero = -0 no es una construcción así y no producirá un 0 negativo.

Para las líneas siguientes, supondré que el 0 negativo se produjo en una forma bit a bit, en una implementación que lo admite .

El estándar C ++ no habla en absoluto de ceros negativos, y el estándar C simplemente dice de ellos que su existencia depende de la implementación. No pude encontrar ningún párrafo que dijera explícitamente si un cero negativo debe o no ser igual a un cero normal para el operador relacional o de igualdad.

Así que citaré en referencia C: 6.5.8 Operadores relacionales §6

Cada uno de los operadores <(menor que),> (mayor que), <= (menor o igual que) y> = (mayor que o igual a) rendirá 1 si la relación especificada es verdadera y 0 si es falso.92) El resultado tiene tipo int.

y en C ++ 5.9 operadores relacionales [expr.rel] §5

Si ambos operandos (después de las conversiones) son de tipo aritmético o de enumeración, cada uno de los operadores arrojará verdadero si la relación especificada es verdadera y falsa si es falsa.

Mi interpretación del estándar es que una implementación puede permitir una representación alternativa del valor entero 0 ( cero negativo ) pero sigue siendo una representación del valor 0 y debe funcionar en consecuencia en cualquier expresión aritmética, porque C 6.2.6.2 Tipos enteros § 3 dice:

los ceros negativos se generarán solo por [...] los operadores +, -, *, / y% donde un argumento es un cero negativo y el resultado es cero

Eso significa que si el resultado no es 0, un 0 negativo debería funcionar como un cero normal.

Entonces estas dos líneas al menos están perfectamente definidas y deberían producir 1 :

std::cout<<(1 << negzero)<<std::endl; std::cout<<(1 >> negzero)<<std::endl;

Esta línea se define claramente como dependiente de la implementación:

std::cout<<(~negzero)<<(~zero)<<std::endl;

porque una implementación podría tener bits de relleno. Si no hay bits de relleno, en la arquitectura de complemento de uno ~zero es negzero , por lo que ~negzero debería producir un 0 pero no pude encontrar en el estándar si un cero negativo debería mostrarse como 0 o como -0 . Un punto flotante negativo 0 debe mostrarse con un signo menos, pero nada parece explícito para un valor negativo entero .

Para las últimas 3 líneas que involucran operadores relacionales y de igualdad, no hay nada explícito en el estándar, entonces yo diría que es implementación definida

TL / DR:

Depende de la implementación:

std::cout<<(negzero < zero)<<std::endl; std::cout<<(negzero <= zero)<<std::endl; std::cout<<(negzero == zero)<<std::endl; std::cout<<(~negzero)<<(~zero)<<std::endl;

Perfectamente definido y debería producir 1:

std::cout<<(1 << negzero)<<std::endl; std::cout<<(1 >> negzero)<<std::endl;


Primero que nada, las arquitecturas de complemento (o incluso distinguir el cero negativo) son bastante raras, y hay una razón para eso. Es básicamente más fácil (en cuanto al hardware) agregar dos complementos que el complemento de uno.

El código que ha publicado no parece tener un comportamiento indefinido o incluso un comportamiento de implementación definido, probablemente no debería dar como resultado un cero negativo (o no debe distinguirse del cero normal).

Los ceros negativos no deberían ser tan fáciles de producir (y si logra hacer eso, se trata, en el mejor de los casos, de un comportamiento definido). Si se trata de una arquitectura de complemento único, se producirían mediante ~0 (inversión en bits) en lugar de -0 .

El estándar de C ++ es bastante vago sobre la representación real y los requisitos sobre el comportamiento de los tipos básicos (lo que significa que la especificación solo trata con el significado real del número). Lo que esto significa es que básicamente no tienes suerte al relacionar la representación interna del número y su valor real. Entonces, incluso si hiciste esto bien y usaste ~0 (o la forma que sea adecuada para la implementación), la norma todavía no parece molestar con la representación ya que el valor del cero negativo sigue siendo cero.

#define zero (0) #define negzero (~0) std::cout<<(negzero < zero)<<std::endl; std::cout<<(negzero <= zero)<<std::endl; std::cout<<(negzero == zero)<<std::endl; std::cout<<(~negzero)<<(~zero)<<std::endl; std::cout<<(1 << negzero)<<std::endl; std::cout<<(1 >> negzero)<<std::endl;

las tres primeras líneas deberían producir el mismo resultado que si se definiera negzero como zero . La tercera línea debe dar dos ceros (ya que el estándar requiere que 0 se represente como 0 sin signo-signo). Los dos últimos deberían tener salida.

Hay algunos consejos (sobre cómo producir ceros negativos) que se pueden encontrar en el estándar C, que realmente menciona el cero negativo, pero no creo que haya ninguna mención acerca de que deberían comparar menos de cero normal. El estándar C sugiere que el cero negativo podría no sobrevivir en el almacenamiento en el objeto (es por eso que evité eso en el ejemplo anterior).

La forma en que se relacionan C y C ++ es razonable pensar que un cero negativo se produciría de la misma manera en C ++ que en C, y el estándar parece permitir eso. Mientras que el estándar C ++ permite otras formas (a través de un comportamiento indefinido), pero ningún otro parece estar disponible a través de un comportamiento definido. Entonces, es bastante cierto que si una implementación en C ++ es capaz de producir ceros negativos de una manera razonable, sería lo mismo que para una implementación C similar.