Fatorial Desajeitado: Vamos por Partes!
- #Java
Parecia fácil demais para ser verdade. Para esse desafio, cuja entrada é um número inteiro qualquer, parecia bastar fazer a sequência decrescente até o 1, mas inserindo um operador de multiplicação, divisão, soma e subtração, entre eles, respectivamente. Pronto. Só que não. Ir direto para o código é uma armadilha em que as vezes caímos “desajeitados”!
Lembrando do Pensamento Computacional, dividir um problema complexo em etapas menores era a solução para esse desafio. Três etapas básicas:
a. Entender como o problema é resolvido de forma tradicional (no “mundo real”).
b. Traduzir essa solução para instruções que possam ser aplicadas em computador (algoritmo).
c. Implementar o algoritmo em uma linguagem de programação (nesse caso, Java).
Abaixo descrevo a estrutura utilizada, e no final, os desafios que foram aparecendo durante o desenvolvimento em que cada etapa foi dividida em sub passos.
A ) Entender como o problema é resolvido de forma tradicional (no “mundo real”).
Como esse é um problema matemático, basta lápis e caderno.
1. Resolver alguns exemplos no caderno.
Fonte da imagem: elaborada pelo autor (faltou acender as luzes :D ).
2. Analisar quais padrões existem nessa solução: quais passos você usa e quais atividades repete até chegar ao resultado.
Fonte da imagem: elaborada pelo autor.
3. Detalhar esses padrões em uma linguagem natural (descrição narrativa), que você entenda.
Exemplo:
-Criar uma lista decrescente de 10 a 1;
-Considerar uma sequência de 1 a 4 para os números até o final da expressão.
-Inserir o operador correspondente depois de cada número.
-Repetir a sequência de operadores depois de quatro números.
-Realizar a operação para o primeiro e o segundo números e copiar o terceiro e o quarto.
-[...].
B) Traduzir essa solução para instruções que possam ser aplicadas em computador (algoritmo).
1. Transformar em linguagem de algoritmo os passos da solução. Neste exemplo, usei um pseudocódigo, mas se preferir, faça em diagramas de blocos ou fluxogramas:
Fonte da imagem: elaborado pelo autor, utilizando Portugol Webstudio: https://dgadelha.github.io/Portugol-Webstudio/
2. Fazer os testes de mesa: aplicar o algoritmo no papel com alguns valores para verificar o resultado.
3. É importante revisar se ainda existem padrões que se repetem e, portanto, poderiam ser resumidos e simplificados, evitando a redundância e simplificando o entendimento do código.
C) Implementar o algoritmo em uma linguagem de programação.
1. Escrever na linguagem de programação baseado no algoritmo.
2. Adaptar para a sintaxe da linguagem de programação escolhida.
(Uma parte do código em Java, utilizando condicionais e funções definidas no algoritmo para reduzir a redundância de código).
Fonte da imagem: elaborada pelo autor.
3. Fazer os testes a cada nova função acompanhando se as saídas estão conforme o esperado.
MEUS DESAFIOS:
1. Como inserir os operadores?
Descobri que não existe um tipo de dados em Java em que se possa atribuir um operador matemático. Seria útil, por exemplo, concatenar valores e operadores, reduzindo um programa extenso em um único comando. Até montei uma expressão com String, para teste, mas não passa daí. A estratégia então teria que ser criar funções para calcular cada passo.
2. Que tipo de lista usar?
Depois de alguns testes, defini que a classe List atendia a minha solução, pela praticidade:
List<Integer> lista = new ArrayList<>();
3. Como desenvolver as funções?
Para o primeiro cálculo, considerar que dos quatro operadores (*, /, +, -) executar somente a multiplicação, mas só para os números na posição certa.
Exemplo:
A lista é: (10, 9, 8, 7, 6, 5, 4, 3, 2, 1).
A expressão seria: 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1.
Então, calcular da lista: (10 * 9), 8, 7, (6 * 5), 4, 3, (2 * 1).
E fazer uma nova lista para receber os resultados.
Padrão:
Repetir até o final da lista {
(Contar quatro)
primeiro multiplicar segundo;
copiar terceiro;
copiar quarto;
se tem um próximo (ele vira o primeiro);
}
Fim do primeiro cálculo, o resultado: (90, 8, 7, 30, 4, 3, 2).
Repetir esse processo para divisão e soma.
Mas se pegar a lista que é resultado da divisão (11, 7, 7, 3, 2) e aplicar a soma diretamente como fiz nos operadores anteriores:
· considerando a expressão 11 + 7 – 7 + 3 – 2.
· o cálculo da lista: (11 + 7), (7 + 3), 2.
· a nova lista seria: (18, 11, 2).
· E o resultado da subtração no próximo passo seria 5. Errado!
Porque o resultado de 11 + 7 - 7 + 3 - 2, é 12. Então, tenho que aplicar o sinal de negativo antes desse passo para dar certo.
Para reescrever a lista (11, 7, 7, 3, 2) em (11, 7, -7, 3, -2):
Copiar os dois primeiros.
Repetir até o fim da lista {
próximo multiplicar por -1;
Copiar próximo;
}
Pronto, resultado 11, 7, -7, 3, -2.
Para somar, percorrer a última lista somando cada valor:
resultado = o primeiro valor da lista;
Repetir até o fim da lista {
resultado = resultado + próximo;
}
Fiz os testes e tudo funcionou!
Conclusão.
Nesse desafio, a lógica de programação através de um algoritmo previamente planejado faz o processo fluir. Lembrando do curso de Pensamento Computacional, dividimos o problema em partes menores que vão nos ajudar a chegar ao resultado.
Considerando que temos pontos de vista particulares, alguns mestres de computação dizem ser praticamente impossível duas pessoas desenvolverem códigos exatamente iguais para o mesmo problema, visto que em cada passo da solução podemos tomar decisões únicas. Aqui, descrevi uma abordagem que segui para esse desafio (como iniciante) mas sabendo que podem existir métodos mais eficientes ou mais escaláveis para gerar o mesmo resultado.
Se preferir mais detalhes desse código para comparação, deixo abaixo o repositório no Github.
Espero ter sido de ajuda!
Obrigado pela leitura!
https://github.com/RicardoMoraesG/desafio-dio-2/blob/master/src/FatorialDesajeitado.java