paulo1205
(usa Ubuntu)
Enviado em 12/09/2016 - 05:52h
XProtoman escreveu:
Quem está certo? Python, C(fprintf) ou minha implementação?
Estou supondo que as 3 estão corretas, no caso C e minha implementação acho que são o mesmo resultado e tem a proposta igual, já Python é um número negativo, -128(0x80) deve ter sido coincidência.
No caso de Python, você precisa tomar o cuidado de lembrar que a saída da função
hex () é do tipo string. Se você tomar a saída dessa função e tentar operar com ela como se fosse um inteiro, sem explicitamente a converter para inteiro, vai tomar erros.
>>> a=hex(-50)
>>> a
'-0x32' <-- NOTE QUE ESTÁ ENTRE APÓSTROFOS
>>> 5-a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'int' and 'str'
>>> 5-int(a,16)
55
Em C, você falou de usar
int8_t , e disse que
fprintf () produz “0xFFFFFFC0” para
-64 . Como você está trabalhando com
int8_t , você deveria ter usado a conversão
"%hhX" , em lugar de apenas
"%X" . Fez isso?
Veja a diferença:
#include <stdio.h>
#include <stdint.h>
int main(void){
int8_t x=-64;
printf("%X\n", x);
printf("%hhX\n", x);
return 0;
}
Se compilar o rodar o programa acima, você vai receber o seguinte resultado.
FFFFFFC0
C0
Lembre-se que quando se usa
printf () -- ou, na verdade, qualquer outra função que utilize quantidade variável de argumentos -- todos os argumentos de tipos inteiros com tamanho menor que o tamanho de
int (ou
unsigned int ) são convertidos para
int (ou
unsigned int ), e dados do tipo
float são convertidos para
double . Além disso quando um valor negativo é convertido para um inteiro com maior quantidade de bits, o sinal é preservado.
unsigned char a=255;
signed char b=a; /* Nos nossos PCs, isso faz b=-1. */
/* Na memória, tanto a como b têm um valor 0xFF. */
int ia=a, ib=b; /* Suponho que int tem 32 bits. */
/* ia==255 (a é unsigned e ia é grande o bastante para acomodar o valor real de a). */
/* ib==-1 (b é signed, e o o sinal é levado em conta na hora de estender o número). */
/* Na memória, ia contém 0x000000FF, e ib contém 0xFFFFFFFF. */
Outro aspecto desta discussão é que nós estamos supondo um sistema de representação numérica que usa complemento a 2. Com essa suposição, a faixa de valores de
int8_t vai de
-128 (
0x80 ) a
127 (
0x7F ). Isso cria um descompasso na quantidade de números negativos ou positivos que podem ser representados (128 negativos e 127 positivos -- lembrando que zero não é positivo nem negativo), e consequentemente, um dos valores extremos que não se comporta bem quando se tenta obter seu simétrico.
Existem outras representações possíveis, como, por exemplo magnitude com sinal (um bit reservado para o sinal, e o resto representando quão longe de zero está o número; o simétrico de um número se obtém pela simples inversão do bit de sinal) e complemento a 1 (o simétrico de um número é a inversão de todos os seus bits). Uma característica marcantes desses dois últimos sistemas é que ambos possuem duas representações possíveis para o valor zero: uma com o bit de sinal ligado, e outra com ele desligado.
C não especifica nenhuma forma de representar internamente os números. Em princípio, qualquer representação interna é válida, desde que alguns limites mínimos sejam respeitados e que as operações com os números funcionem de acordo com o comportamento descrito para elas.
Geralmente os nossos PCs usam internamente complemento a 2 para inteiros porque é mais simples construir circuitos elétricos usando essa representação, e nossos compiladores C usam essa implementação e a deixam transparecer sobre os nossos dados inteiros. Mas essa transparência com a qual estamos relativamente habituados não deve ser assumida como sempre verdadeira se nós quisermos escrever um programa realmente portável.
Por outro lado, nós também estamos habituados a usar representação de magnitude com sinal, especialmente para números de ponto flutuante. Inclusive a existência de um “zero negativo” é às vezes desejável para indicar um valor com todas as propriedades de um valor negativo, porém tão pequeno que não pode ser representado com precisão suficiente por uma magnitude maior que zero (por exemplo “
-pow(10, -1000) ”). Mas também não devemos assumir que essa representação de ponto flutuante será sempre verdadeira: podem existir outras máquinas com representações diferentes, e o padrão do C não favorece nenhuma representação em particular, desde que as propriedades da operações sejam satisfeitas.
Já com Python, eu não conheço o suficiente da linguagem para saber se as regras são tão abertas como as do C, ou se ainda mais abertas. Parece-me que Python não faz amarração a tipos nativos -- tanto é que geralmente se consegue representar números gigantes sem nenhuma biblioteca adicional.