[PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Projecto de leitura e escrita para Excel terminado. Aqui fica o código (com comentários ao longo):
Com esta ferramenta à mão, vou passar ao debugging mais intensivo e extensivo da Classe Extenso, para poder fechar o projecto.
Code: Select all
package com.company;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.*;
import static com.company.Extenso5.extenso;
public class Main {
public static void main(String[] args) {
try{
// Abrir canal de "leitura/input" e carregar ficheiro
FileInputStream file = new FileInputStream(new File( "C:\\Temp\\Java\\translate.xlsx"));
// Declaraçao e instanciação de objectos POI, para oe elementos da folha de cálculo
XSSFWorkbook workbook = new XSSFWorkbook(file);
Sheet sheet = workbook.getSheetAt(0);
Cell cell;
Row row;
// Quantas linhas tem a folha
int rows = sheet.getPhysicalNumberOfRows();
// Loop pelas linhas com informação
String getterS, extVal;
for(int r = 1; r < rows; r++) {
row = sheet.getRow(r);
if(row != null) {
cell = row.getCell((short)0);
if(cell != null) {
// READ da célula
getterS = String.valueOf(cell.getNumericCellValue());
getterS = getterS.substring(0, getterS.indexOf("."));
// Obter o valor por extenso
extVal = extenso(getterS);
// WRITE para a célula (col + 1)
cell = row.createCell(1);
cell.setCellValue(extVal);
}
}
}
// Abrir um "canal de output e Gravação", paralelo ao de Leitura
FileOutputStream output = new FileOutputStream(new File( "C:\\Temp\\Java\\translate.xlsx"));
// Gravar
workbook.write(output);
// Fechar operações
output.close();
workbook.close();
file.close();
System.out.println("Terminado.");
}
catch (FileNotFoundException naoHaFicheiro){
System.out.println("No file: " + naoHaFicheiro);
}
catch (IOException erroIO){
System.out.println("IO Error: " + erroIO);
}
}
}
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Ok, nova inflexão não pleaneada no projecto.
(está a começar a ser um hábito...)
Sucede que (também) há uma limitação na extensão que o tipo de dados "numérico" consegue suportar quando estou a fazer a importação de valores de uma célula de Excel através do mecanismo acima descreito. Na prática, isto significa que o programa resulta bem até determinada grandeza, e depois começa a dar valores que não têm nada a ver. Para contornar esta limitação, a solução mais óbvia seria formatar os dados logo na folha de Excel para serem lidos como "String" (implica colocar um apóstrofe antes do número), mas se optar por essa via deixo de conseguir manipular a informação como se fosse um número - deixo de poder incrementar as células facilmente, deixo de poder fazer operações matemáticas sobre os dados e deixo de poder ver os separadores de milhar. Em suma, perco as vantagens que iria ganhar em fazer o debugging por esta via.
Portanto, novo mini-projecto à vista. Desta vez vou mesmo correr TODOS os números de um a um até 1 Decilião e obter para cada um o respectivo extenso, só que vou mandar os dados para um ficheiro de texto. Se à partida esta ideia até parece ser simples e descomplexada (
), se começarmos a pensar nas implicaçõe práticas a coisa toma dimensões sobre-humanas, porque o ficheiro de output será, previsivelmente enormérrimo... 1 decilião de linhas, com números e texto à mistura, é muita fruta.
Aceitam-se apostas para prever o espaço que vai ocupar em disco, e o tempo que vai demorar ao programa construir um ficheiro assim.
(isto é giro até para fazer benchmarks...
*** para além de que devem registar-se variações consideraveis de sistema para sistema...)
Programaticamente parece não ser nada complicado. Faz-se um loop que incrementa uma variável de um a um até 1 decilião, e a cada pass manda o resultado do extenso para o ficheiro.
Pretende-se isto, dentro de um ficheiro .txt:
1 - um
2 - dois
3 - três
4 - quatro
...
1.000... 000 - um decilião

Sucede que (também) há uma limitação na extensão que o tipo de dados "numérico" consegue suportar quando estou a fazer a importação de valores de uma célula de Excel através do mecanismo acima descreito. Na prática, isto significa que o programa resulta bem até determinada grandeza, e depois começa a dar valores que não têm nada a ver. Para contornar esta limitação, a solução mais óbvia seria formatar os dados logo na folha de Excel para serem lidos como "String" (implica colocar um apóstrofe antes do número), mas se optar por essa via deixo de conseguir manipular a informação como se fosse um número - deixo de poder incrementar as células facilmente, deixo de poder fazer operações matemáticas sobre os dados e deixo de poder ver os separadores de milhar. Em suma, perco as vantagens que iria ganhar em fazer o debugging por esta via.
Portanto, novo mini-projecto à vista. Desta vez vou mesmo correr TODOS os números de um a um até 1 Decilião e obter para cada um o respectivo extenso, só que vou mandar os dados para um ficheiro de texto. Se à partida esta ideia até parece ser simples e descomplexada (

Aceitam-se apostas para prever o espaço que vai ocupar em disco, e o tempo que vai demorar ao programa construir um ficheiro assim.




Programaticamente parece não ser nada complicado. Faz-se um loop que incrementa uma variável de um a um até 1 decilião, e a cada pass manda o resultado do extenso para o ficheiro.
Pretende-se isto, dentro de um ficheiro .txt:
1 - um
2 - dois
3 - três
4 - quatro
...
1.000... 000 - um decilião
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Novo choque de frente entre conceito intencionado e concretização.
Desenvolvi o tal programa para mandar resultados para ficheiros .txt ...
... e comecei a testar progressivamente. Primeiro com 1.000 números, depois com 10.000, e só segui até aos 10.000.000, devido ao espaço e tempo que demoram a criar.
Pela imagem seguinte dá para ter uma ideia:

Se com 10.000.000 de registos demora quase 5 minutos a criar um ficheiro de quase 800MB's, e se os ficheiros crescem na razão e proporção directa da grandeza dos números (multiplicando por 10 de um lado, o ficheiro gerada passa a ocupar 10x mais em disco), rapidamente esgotaria o espaço disponível em disco.
Assim por contas rápidas, cem milhões daria 8GB, mil milhões daria 80GB, dez mil milhões daria 900GB, cem mil milões daria 9PB, e um bilião daria 90PB...
Não deve haver sistema no mundo com espaço suficiente em disco para guardar um ficheiro com os extensos dos números todos entre 1 e 1 decilião.


Desenvolvi o tal programa para mandar resultados para ficheiros .txt ...
Code: Select all
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigInteger;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import static com.company.Extenso.extenso;
class Main {
public static void main(String[] args) {
OperatingSystemMXBean osBean = (com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
String osName = osBean.getName();
String osVersion = osBean.getVersion();
int cores = osBean.getAvailableProcessors();
String cpuName = System.getenv("PROCESSOR_IDENTIFIER");
Long memSize = osBean.getTotalPhysicalMemorySize();
try {
BigInteger limite = new BigInteger("10000000");
double init, finit;
init = System.currentTimeMillis();
PrintStream out = new PrintStream(new FileOutputStream(
"c:\\temp\\java\\coding\\DebuggerExt\\output.txt", false), false);
System.setOut(out);
for (BigInteger loopVar = new BigInteger("1");
loopVar.compareTo(limite) <= 0;
loopVar = loopVar.add(BigInteger.valueOf(1))) {
String sepMilhares = String.format("%,d", loopVar);
System.out.println(sepMilhares + " - " + extenso(loopVar.toString()));
}
finit = System.currentTimeMillis();
System.out.println("Tempo decorrido: " + ((finit - init)/1000D )+ " segundos");
System.out.println();
System.out.println("SO: " + osName);
System.out.println("Versao SO: " + osVersion);
System.out.println("Tipo CPU: " + cpuName);
System.out.println("\"Cores\" CPU: " + cores);
System.out.println("Memoria (MBytes arred.): " + memSize/1024/1024);
}
catch(IOException e1) {
System.out.println("Error during reading/writing");
}
}
}
Pela imagem seguinte dá para ter uma ideia:

Se com 10.000.000 de registos demora quase 5 minutos a criar um ficheiro de quase 800MB's, e se os ficheiros crescem na razão e proporção directa da grandeza dos números (multiplicando por 10 de um lado, o ficheiro gerada passa a ocupar 10x mais em disco), rapidamente esgotaria o espaço disponível em disco.
Assim por contas rápidas, cem milhões daria 8GB, mil milhões daria 80GB, dez mil milhões daria 900GB, cem mil milões daria 9PB, e um bilião daria 90PB...

Não deve haver sistema no mundo com espaço suficiente em disco para guardar um ficheiro com os extensos dos números todos entre 1 e 1 decilião.

«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
- Rui Santos
- Site Admin
- Posts: 6210
- Joined: June 4th, 2001, 11:42 pm
- Location: Portugal - Lisboa / MAC
- Contact:
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Podes implementar uma classe de zip :), que te permitirá graver o ficheiro comprimido que nenhum PC descomprimirá 

Rui Santos - 54 Anos | 23 Anos DVDMania
DVD/BR | Jogos | Life is Short, Play More | FB Collectors HV-PT
DVD/BR | Jogos | Life is Short, Play More | FB Collectors HV-PT
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Sim, e depois colocar um ficheiro numa dessas "time-capsules", para abrir daqui a 50 anos. Pode ser que então já se consiga descomprimir.Rui Santos wrote: March 11th, 2019, 11:03 pm Podes implementar uma classe de zip :), que te permitirá graver o ficheiro comprimido que nenhum PC descomprimirá![]()

Só para efeitos de Benchmarking, ainda vou testar a mesma operação num PC mais potente, e com um disco SDD (que aqui vai fazer, supostamente, muita diferença, pois a operação mais morosa é a do registo no ficheiro).
O post anterior tem um ... bug...

Já agora:
https://whatsabyte.com/
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz
Vou para já fechar este projecto.
Fiz uma bateria de testes mais ou menos aleatórios e os resultados pareceram-me certos e consistentes.
O código final já optimizado, devidamente encapsulado e facilmente escalável, para a classe Extenso (permitindo obter resultados até à ordem do Decilião = inteiros com 66 algarismos), é o seguinte:
(código em Java - compila em JDK8 e versões posteriores)
A classe como está já não permite utilização directa a partir da linha de comando (como em alguns exemplos acima) e tem mesmo de ser chamada a partir de outra classe, ou, melhor maneira, utilizada através do único método de entrada, que tem por nome "extenso", e que aceita uma String como argumento.
Fiz uma bateria de testes mais ou menos aleatórios e os resultados pareceram-me certos e consistentes.
O código final já optimizado, devidamente encapsulado e facilmente escalável, para a classe Extenso (permitindo obter resultados até à ordem do Decilião = inteiros com 66 algarismos), é o seguinte:
(código em Java - compila em JDK8 e versões posteriores)
Code: Select all
import java.math.BigInteger;
public class Extenso {
public static String extenso(String inputVal) {
boolean isNeg = false;
if (inputVal.startsWith("-")) {
isNeg = true;
inputVal = inputVal.substring(1);
}
// Caçar caracteres não permitidos:
char[] diagS = inputVal.toCharArray();
for (char algarismo : diagS) {
if (!Character.isDigit(algarismo)) {
return "*** EXITING *** A express\u00E3o cont\u00E9m caracteres n\u00E3o num\u00E9ricos.";
}
}
// Chamada ao método "nuclear": para triagem da grandeza e seguimento do fluxo
return (isNeg ? "menos " : "") + triagemInicial(inputVal);
}
private static String triagemInicial(String i) {
String valorFinal;
BigInteger inputVal = new BigInteger(i);
if (inputVal.compareTo(BigInteger.valueOf(1_000_000)) < 0) {
int inputValNum = Integer.parseInt(i);
if (inputValNum < 20) {
valorFinal = deZeroaDezanove(inputValNum);
} else if (inputValNum <= 100) {
valorFinal = menorQueCem(inputValNum);
} else if (inputValNum <= 1000) {
valorFinal = menorQueMil(inputValNum);
} else { // <1_000_000
valorFinal = menorQueUmMilhao(inputValNum);
}
} else { // >= 1_000_000
BigInteger milhaoComparador = new BigInteger("1" + "000000");
BigInteger iterador = inputVal;
int tamanhoGrandeza = 0;
String extensoGrandeza = "1";
while (iterador.compareTo(milhaoComparador) >= 0) {
tamanhoGrandeza += 1;
extensoGrandeza += "000000";
iterador = iterador.divide(milhaoComparador);
}
String preExt;
switch (tamanhoGrandeza) {
case 1: // < 1_000_000_000_000, menor do que 1 Bilião
preExt = "milh";
break;
case 2: // < 1_000_000_000_000_000_000, menor do que 1 Trilião
preExt = "bili";
break;
case 3: // < 1_000_000_000_000_000_000, menor do que 1 Quatrilião
preExt = "trili";
break;
case 4: // < 1 Quintilião ....
preExt = "quatrili";
break;
case 5: // < 1 Sextilião
preExt = "quintili";
break;
case 6: // < 1 Setptilião
preExt = "sextili";
break;
case 7: // < 1 Octilião
preExt = "septili";
break;
case 8: // < 1 Nonilião
preExt = "octili";
break;
case 9: // < 1 Decilião
preExt = "nonili";
break;
case 10: // < 1 Undecilião
preExt = "decili";
break;
// Acrescentar aqui novas grandezas necessárias
default:
preExt = "nulo";
}
valorFinal = (preExt != "nulo"
? metodoMilionario(inputVal.toString(), preExt, extensoGrandeza)
: "Inteiro demasiado grande - ainda n\u00E3o suportado.");
}
return valorFinal;
}
private static String deZeroaDezanove(int i) {
String valorFinal;
switch (i) {
case 0:
valorFinal = "zero";
break;
case 1:
valorFinal = "um";
break;
case 2:
valorFinal = "dois";
break;
case 3:
valorFinal = "tr\u00EAs";
break;
case 4:
valorFinal = "quatro";
break;
case 5:
valorFinal = "cinco";
break;
case 6:
valorFinal = "seis";
break;
case 7:
valorFinal = "sete";
break;
case 8:
valorFinal = "oito";
break;
case 9:
valorFinal = "nove";
break;
case 10:
valorFinal = "dez";
break;
case 11:
valorFinal = "onze";
break;
case 12:
valorFinal = "doze";
break;
case 13:
valorFinal = "treze";
break;
case 14:
valorFinal = "catorze";
break;
case 15:
valorFinal = "quinze";
break;
case 16:
valorFinal = "dezasseis";
break;
case 17:
valorFinal = "dezassete";
break;
case 18:
valorFinal = "dezoito";
break;
case 19:
valorFinal = "dezanove";
break;
default:
valorFinal = "BUG eating method deZeroaVinte";
}
return valorFinal;
}
private static String menorQueCem(int i) {
String valorFinal;
if (i % 10 == 0) {
valorFinal = deVinteaNoventaeNove(i);
} else {
valorFinal = deVinteaNoventaeNove(i - (i % 10)) + " e "
+ deZeroaDezanove(i % 10);
}
return valorFinal;
}
private static String deVinteaNoventaeNove(int i) {
String valorFinal;
switch (i) {
case 20:
valorFinal = "vinte";
break;
case 30:
valorFinal = "trinta";
break;
case 40:
valorFinal = "quarenta";
break;
case 50:
valorFinal = "cinquenta";
break;
case 60:
valorFinal = "sessenta";
break;
case 70:
valorFinal = "setenta";
break;
case 80:
valorFinal = "oitenta";
break;
case 90:
valorFinal = "noventa";
break;
case 100:
valorFinal = "cem";
break;
default:
valorFinal = "A BUG is chewing method deVinteaNoventaeNove";
}
return valorFinal;
}
private static String menorQueMil(int i) {
String valorFinal;
if (i % 100 == 0)
valorFinal = deCemaNoveNoveNove(i);
else if (i < 200)
valorFinal = "cento e " + triagemInicial(String.valueOf(i % 100));
else
valorFinal = deCemaNoveNoveNove(i - i % 100) + " e " + triagemInicial(String.valueOf(i % 100));
return valorFinal;
}
private static String deCemaNoveNoveNove(int i) {
String valorFinal;
switch (i) {
case 200:
valorFinal = "duzentos";
break;
case 300:
valorFinal = "trezentos";
break;
case 400:
valorFinal = "quatrocentos";
break;
case 500:
valorFinal = "quinhentos";
break;
case 600:
valorFinal = "seiscentos";
break;
case 700:
valorFinal = "setecentos";
break;
case 800:
valorFinal = "oitocentos";
break;
case 900:
valorFinal = "novecentos";
break;
case 1000:
valorFinal = "mil";
break;
default:
valorFinal = "A BUG is chewing method deCemaNoveNoveNove";
}
return valorFinal;
}
private static String menorQueUmMilhao(int i) {
String valorFinal;
if (i % 1000 == 0) {
valorFinal = triagemInicial(String.valueOf(i / 1000)) + " mil";
} else if (i % 1000 <= 100 || ((i % 1000) % 100) == 0) {
if (i / 1000 == 1) {
valorFinal = "mil e " + triagemInicial(String.valueOf(i % 1000));
} else {
valorFinal = triagemInicial(String.valueOf(i / 1000)) + " mil e " + triagemInicial(String.valueOf(i % 1000));
}
} else {
if (i / 1000 == 1) {
valorFinal = "mil " + triagemInicial(String.valueOf(i % 1000));
} else {
valorFinal = triagemInicial(String.valueOf(i / 1000)) + " mil " + triagemInicial(String.valueOf(i % 1000));
}
}
return valorFinal;
}
private static boolean levaE(String grandeza) {
// Método para verificar a necessidade de
// utilização de um "e" logo após a grandeza maior do inteiro.
// Exs:
// 1.000.001 = "um milhão e um" (verifica as condições) - devolve TRUE
// 1.000.200 = "um milhão e duzentos" (verifica as condições) - devolve TRUE
// 1.200.000 = "um milhão e duzentos mil" (verifica as condições) - devolve TRUE
// 1.000.101 = "um milhão, cento e um" (NÃO verifica as condições - logo a seguir a milhão, leva uma vírgula) - devolve FALSE
boolean comE = false;
BigInteger grandezaA = new BigInteger(grandeza);
BigInteger grandezaB = new BigInteger(grandeza);
int powerVal = 0;
while (grandezaB.compareTo(BigInteger.valueOf(1_000_000)) >= 0) {
grandezaB = grandezaB.divide(BigInteger.valueOf(1_000_000));
powerVal++;
}
BigInteger resto = new BigInteger("1");
BigInteger comparador = new BigInteger("1000000"); // Um milhão
comparador = comparador.pow(powerVal);
resto = grandezaA.mod(comparador);
// Teste Condição 1: Resto da grandeza a dividir pelo comparador é menor ou igual a 100 (ex input: 1.0000.100)
if (resto.compareTo(BigInteger.valueOf(100)) <= 0) {
comE = true;
return comE;
} else {
comE = false;
}
// Condição 2
BigInteger resto2 = new BigInteger("1");
BigInteger comparador2 = new BigInteger("1");
comparador2 = comparador.divide(BigInteger.valueOf(10));
for (BigInteger z = new BigInteger("100000"), x = new BigInteger("1000");
z.compareTo(comparador2) <= 0;
z = z.multiply(BigInteger.valueOf(1_000)), x = x.multiply(BigInteger.valueOf(10))) {
resto2 = resto.mod(x);
if (resto.compareTo(z) <= 0 && resto2.compareTo(BigInteger.valueOf(0)) == 0) {
comE = true;
return comE;
} else {
comE = false;
}
}
// Condição 3
BigInteger resto3 = new BigInteger("1");
for (BigInteger w = new BigInteger("1000"), y = new BigInteger("100");
w.compareTo(comparador) <= 0;
w = w.multiply(BigInteger.valueOf(1_000)), y = y.multiply(BigInteger.valueOf(1000))) {
resto3 = resto.mod(y);
if (resto.compareTo(w) <= 0 && resto3.compareTo(BigInteger.valueOf(0)) == 0) {
comE = true;
return comE;
} else {
comE = false;
}
}
return comE;
}
private static String metodoMilionario(String i, String preExt, String grand) {
// Médodo para trabalhar todas as grandezas acima de 1 milhão.
// a uniformidade de critérios na terminologia dos número acima desta grandeza
// permite a recursividade deste método.
BigInteger grandeza = new BigInteger(grand);
String singular = preExt + "\u00E3o", plural = preExt + "\u00F5es";
String valorFinal;
BigInteger inputVal = new BigInteger(i);
BigInteger i2 = inputVal.divide(grandeza);
BigInteger i3 = inputVal.mod(grandeza);
if (i3.compareTo(BigInteger.valueOf(0)) == 0) {
if (inputVal.compareTo(grandeza) == 0) {
valorFinal = "um " + singular;
} else {
inputVal = inputVal.divide(grandeza);
valorFinal = triagemInicial(inputVal.toString()) + " " + plural;
}
} else if (levaE(i)) {
if (i2.compareTo(BigInteger.valueOf(1)) == 0) {
valorFinal = "um " + singular + " e " + triagemInicial(i3.toString());
} else {
valorFinal = triagemInicial(i2.toString()) + " " + plural + " e " + triagemInicial(i3.toString());
}
} else {
if (i2.compareTo(BigInteger.valueOf(1)) == 0) {
valorFinal = "um " + singular + ", " + triagemInicial(i3.toString());
} else {
valorFinal = triagemInicial(i2.toString()) + " " + plural + ", " + triagemInicial(i3.toString());
}
}
return valorFinal;
}
}
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva
«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death
Câmara Subjectiva