problema1.c

/* Este C !!!  Veja como um programador inexperiente pode ser
 * facilmente enganado por não dominar plenamente a 'filosofia' C de ser
 * 
 * Autor: Elgio Schlemer
 * Data: 30/12/2000
 *
 * Paginas:
 *      http://www.ulbra.tche.br/~elgios/linux
 *      http://www.inf.ufrgs.br/~elgios/linux
 *                 
 *
 * Responda rápido e sem executar: qual o valor de:
 *      (200 * 0,7 ) + 200 ?
 *
 * 340? Tem certeza disso?
 */

#include <stdio.h>
int main()
{
	int a;
	double b;


	b = 200;

	a = (b * 0.7) + b;
	printf("%d\n", a);


	/* Então, a linha acima deverá imprimir a resposta certa, ou
	 * seja, 340, pois:
	 *      b * 0.7   = 140 (200 * 0,7)
	 *      140 + 200 = 340
	 *
	 * Execute e diga o que foi REALMENTE impresso!! Eu espero...
	 */
}

/*****************************************************************
 * 339. Este foi o valor impresso. Porque? Será que você é um dos
 * felizardos a ter ainda um Pentium com problema no processador de
 * ponto flutuante?
 * 
 * Vamos a teoria:
 * 	O C permite que o programador faça coisas estranhas com suas
 * 	variáveis, como atribuir inteiros para variáveis do tipo char
 * 	e vice-versa. Isso significa PODER ao programador, pois é
 * 	possível fazer qualquer coisa, como:
 *
 * 		int a=300;
 * 		char b;
 *
 * 		b=a;
 * 		
 * 	Como é possível 'b' receber o valor de 'a' se o tamanho de
 * 	'b' do tipo char é de apenas um byte, podendo representar
 * 	valores apenas entre 0 a 255 ?
 *
 * 	O C coloca na variável APENAS o que couber nela. Isso é
 * 	conhecido como Conversão implícita de dados. No exemplo acima,
 * 	o C colocará APENAS o primeiro byte da variável a em b.
 * 	Se o programa for compilado e executado na arquitetura intel,
 * 	este byte será o menos sgnificativo, pois a Intel usa
 * 	codificação "Little Endian" para codificar número inteiros. Se
 * 	for em uma arquitetura SUN, o byte será o MAIS significativo,
 * 	pois esta usa o "Big Endian" para codificar inteiros.
 *
 * 	Mas especificamente, 300 é representável por dois bytes,
 * 	expressos em hexadecimal por "01 2C". Executando-se este
 * 	exemplo em uma máquina Intel, temos que 'b' recebe o valor em
 * 	hexa "2C", que é a representação do número "44". Veja:
 *
 * 		printf("%d\n", b);
 *
 * 	O que isso nos importa? Importa que no exemplo:
 * 	
 *		b=200;
 *		a = (b * 0.7) + b; 
 *
 *	a receberá apenas o sbytes menos significativos de b, não
 *	sendo atribuído, no caso de uma variável double, o valor das
 *	casas decimais. Veja o exemplo:
 *
 *		a = 3.99999;
 *
 *	a tem na verdade o valor 3 e não 4, pois o C não faz
 *	arredondamentos. Ele pega somente os bytes que couberem!!
 *	Não importa o quão próximo esta'de 4, o C truncará na virgula,
 *	pegando apenas e tão somente a parte inteira!!
 *
 *	Mais uma vez voltemos ao nosso exemplo:
 *
 *		b=200;
 *		a = (b * 0.7) + b;
 *		
 *	Mas não é o caso, não é verdade? A operação matemática
 *	resultou em um número inteiro (340), sem casas decimais e
 *	portando deveria ser atribuído o valor 340!!
 *
 *	Ai vem a segunda parte da explicação: alguns valores são
 *	impossíveis de se representar em binário!
 *
 *	Vamos fazer uma analogia: em decimal, codificação que usamos
 *	desde a infância, o valor de 1/3 é impossível de ser
 *	representado!! Pode-se chegar bem perto, representando-o como:
 *	0,3333333333333333333333333.... mas nunca o faremos de forma
 *	100% precisa. O mesmo acontece em binário. Alguns número
 *	decimais não são possíveis de se representar e o que se faz é
 *	representar uma aproximação. Execute os exemplos abaixo em um
 *	programa C:
 *
 *		printf("%.30f\n", 0.1);
 *		printf("%.30f\n", 0.2);
 *		printf("%.30f\n", 0.3);
 *		printf("%.30f\n", 0.4);
 *		printf("%.30f\n", 0.5);
 *		printf("%.30f\n", 0.6);
 *		printf("%.30f\n", 0.7);
 *		printf("%.30f\n", 0.8);
 *		printf("%.30f\n", 0.9);
 *
 *	(O parâmetro %.30f instrui o printf a imprimir 30 casas
 *	decimais para o número).
 *
 *	Você notará que eles estão bem próximos, mas não são uma
 *	representação perfeita, assim como 0,333... com infinitos 3,
 *	jamais será a representação precisa de 1/3.
 *
 *	Pela última vez, voltemos ao nosso exemplo:
 *	
 *		b=200;
 *		a = (b * 0.7) + b;
 *
 *	0.7 não é 0.7 de verdade, mas sim:
 *	
 *		0.699999999999999955591079014994...
 *	
 *	Ora, então 200 * 0.7 não é 140, mas sim algo bastante próximo,
 *	como um 139.999999999999999999999999999999...
 *
 *	Logo, o resultado real de nossa atribuição, não é 340, mas sim
 *	algo como:
 *	
 *		339.99999999999999999999999999999999999....
 *		
 *	Ah, mas a conversão de tipos é por truncamento e não por
 *	arredondamento. Não importa quantos 9's existam depois do
 *	ponto, apenas e tão somente a parte inteira será atribuída
 *	para a variável 'a', pois ela é do tipo inteira!!
 *
 *	Isso não é exclusividade da linguagem C, pois é
 *	característica da representação binária. Acontece que
 *	algumas linguagens, como o Pascal, NÃO PERMITEM atribuíções
 *	entre variáveis de tipos diferentes, logo este problema não
 *	existe!
 *	
 *	Pro fim, se você usar double para ambas as variáveis, será o
 *	valor de 340 impresso, como previsto!
 *
 *	Muito cuidado com isto!!
 *	
 * */

Generated by GNU enscript 1.6.1.