Um "grande" problema

2 respostas
R

Pessoal,
Atualmente estou cursando o primeiro período de Tecnologia da Informação e claro, estou estudando também a lógica de programação. Para ir "adiantando" as coisas, já que eu vou ter lógica no primeiro, segundo, terceiro e quarto período, resolvi por conta própria fazer um curso avançado de lógica em um outro lugar privado. Bom, esse outro curso terminou e resolvi entrar em um curso de JAVA privado também para ir adiantando mais ainda as coisas para mim. E então, na aula de hoje de lógica (na faculdade) a professora passou um exercício matemático muito antigo, mas muito mesmo, que eu de certa forma consegui resolver, mas infelizmente está acontecendo uma coisa que eu não estou conseguindo entender, e vou explicar a vocês.

Primeiro, vou expor o exercício.

Uma rainha requisitou os serviços de um monge e disse-lhe que pagaria qualquer preço para que o serviço fosse realizado. O monge, necessitando de alimentos, perguntou à rainha sobre o pagamento, se poderia ser feito com grãos de trigo dispostos em um tabuleiro de xadrez, de tal forma que o primeiro quadro deveria conter apenas um grão e os quadros subsequentes, o dobro do quadro anterior. A rainha achou o trabalho barato e pediu que o serviço fosse executado, sem se dar conta de que seria impossível efetuar o pagamento. Faça um algoritmo para calcular o número de grãos que o monge esperava receber.

Segundo, agora vamos a lógica do problema.

Bom, se um tabuleiro de xadrez tem exatamente 64 posições e na primeira delas tem 1(2^0) grão, então na segunda terá (2^1) grãos, e isso é percorrido até a última posição(64), irá conter 2^63 grãos, então o resultado final seria em teoria somente eu criar uma variável que guardasse a soma dos grãos de todas as posições, certo?

Beleza..beleza.. então vamos agora para a minha lógica feita no VisualG...

algoritmo "A Rainha e o Monge"
var
soma : real
contador : inteiro
inicio
para contador de 0 ate 63 faca
   soma <- soma + 2^contador
fimpara
escreva("O total de grãos é: ", soma)
fimalgoritmo

A saída no VisualG foi "O total de grãos é: 1.84467440737096E19"

Fiquei muito insatisfeito com o certo "E" ali no antepenúltimo dígito e pensei... será que isso é porque o VisualG não consegue trabalhar com números muito grandes, como o caso do meu problema? E logo depois pensei, porque não tentar fazer em JAVA e ver na realidade mesmo o número bruto, o JAVA deve suportar números extremamente grandes...

Então tá, lá vou eu com apenas 2 aulas de JAVA tentar fazer algum "FAIL code" no Eclipse...

Fui tentar traduzir a minha lógica exatamente como tinha feito no VisualG e fiz o seguinte código:

public class RainhaMonge {

	public static void main(String[] args) {

		double soma = 0;

		for (int i = 0; i <= 63; i++) {

			soma = soma + Math.pow(2, i);

		}

	}
	
}

Todo feliz por ter conseguido usar os comandos sem dar nenhum erro no Eclipse apertei Ctrl+F11 e a saída foi...

18446744073709552E19

Putz... fiquei muito grilado por ver o INFERNO de E novamente em meu número e resolvi ir no Google procurar o resultado REAL do problema em questão e encontrei o seguinte resultado no Yahoo! Grupos.

18446744073709551615

Comparando os dois resultados, são bem parecidos sim... mas o meu está arredondado, ou sei la o que significa esse tal E aí... então resolvi perguntar a um amigo meu como faria para resolver tal problema e então ele me sugeriu o seguinte código...

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;

public class RainhaMonge {

	public static void main(String[] args) {

		double soma = 0;

		for (int i = 0; i <= 63; i++) {

			soma = soma + Math.pow(2, i);

		}

		BigDecimal numero = BigDecimal.valueOf(soma);
		NumberFormat nf = NumberFormat
				.getNumberInstance(new Locale("pt", "BR"));
		System.out.println(nf.format(numero));
	}

}

Executando o mesmo... a saída é 18.446.744.073.709.552.000
Ainda sim está diferente do encontrado no Yahoo! Grupos.... que era 18.446.744.073.709.551.615

Comparação:

MEU: 18.446.744.073.709.552.000
Yahoo: 18.446.744.073.709.551.615

Dá pra ver que o JAVA arredondou o meu número... e eu não fiquei nem um pouco satisfeito com isso, quero o número REAL, não quero um arredondamento...
Por favor, me ajudem a pensar sobre o que está ocorrendo? Eu não estou conseguindo entender o motivo do arredondamento... O que eu faço?

2 Respostas

pmlm

Usa BigDecimal nas contas:

import java.math.BigDecimal;  
      
public class RainhaMonge {  
      
    public static void main(String[] args) {  
        BigDecimal DOIS = new BigDecimal(2);
        BigDecimal soma = BigDecimal.ZERO;  
      
        for (int i = 0; i <= 63; i++) {  
      
            soma = soma.add(DOIS.pow(i));  
      
        }  
      
        System.out.println(soma);  
           
    }  
      
}

Ou, numa única linha, sem precisar do ciclo for:

import java.math.BigDecimal;  

public class RainhaMonge {  
      
    public static void main(String[] args) {  
      
        System.out.println(new BigDecimal(2).pow(64).subtract(BigDecimal.ONE));  
           
    }  
      
}
R

plml,

Muito obrigado mesmo pela sua resposta, ela foi muito clara pra mim e fez exatamente o que eu queria, um código enxuto e funcional, essa minha dúvida foi postada também no fórum de discussão do orkut e também obtive algumas respostas legais, mas não tão pequenas quanto a sua! Irei postar abaixo as respostas que obtive apenas a nível de curiosidade mesmo, se puder dar uma analisada depois seria legal! Aproveitando, estou pensando em comprar aquele livro "Use a cabeça JAVA", é bom? é ruim? Tem melhor para iniciantes? Obrigado mesmo plml! E espero mais respostas suas e do pessoal por aí! Valeu!

Código do usuário DEH:

BigDecimal soma = new BigDecimal(0);

for (int i = 0; i <= 63; i++) {

soma = soma.add(new BigDecimal(Math.pow(2, i)));

}

System.out.println(soma);
Criado 31 de maio de 2011
Ultima resposta 31 de mai. de 2011
Respostas 2
Participantes 2