[RESOLVIDO] Conversão de números reais (Fortran double precision)

Olá senhores,

Tenho que carregar um arquivo texto com números reais. Os números carregados serão usados em cálculos mais tarde. Meu problema é o seguinte: o usuário pode usar como separador decimal a vírgula ou o ponto. Se o programa interpretar de forma diferente a que o usuário pensou os cálculos terão resultados errados.

Gostaria que fosse independente do padrão do sistema operacional, que o usuário me diga que usou a vírgula ou o ponto como separador decimal e o software faça os cálculos levando em consideração esta informação. E a independência do padrão usado no sistema operacional que é o problema.

Alguém já passou por algo parecido ou sabe um bom caminho para resolver isso?

Obrigado,

Emerson Luiz dos Santos

Você pode usar a classe java.text.DecimalFormat (método parse), passando ao seu construtor uma instância da classe java.text.DecimalFormatSymbols para indicar qual é o separador de milhares e o caracter para vírgula ou ponto decimal.

Não testei, mas deve ser algo como:

DecimalFormatSymbols dfs = new DecimalFormatSymbols ();
dfs.setGroupingSeparator ('.');
dfs.setDecimalSeparator (',');
DecimalFormat df = new DecimalFormat ("#,##0.00");
double d = df.parse ("1.234.567,89").doubleValue();

Oi Entanglement,

Criei uma classe de teste aqui, infelizmente o resultado não foi o esperado, um dos erros foi que ele não considerou notação científica e nem a notação ".59" para representar "0.59"

Coloquei algumas valores reais de teste, são valores gerados por programas em Fortran.

Pelo que observei dos valores de teste não existe a necessidade do símbolo de agrupamento, só o símbolo decimal mesmo.

Você acha que só manipulando o pattern conseguimos o resultado esperado? Pra mim ficou meio confuso o uso do DecimalFormatSymbols junto com o pattern…

Obrigado pela atenção,

Emerson Luiz dos Santos

Código Java:

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;


public class TesteFormataNumerosReais {

	public void carregarNumeros(String[] numeros) {
		
		numeros[0] = ".00000000";
		numeros[1] = ".1021E+05";
		numeros[2] = "-.2003E-01";
		numeros[3] = ".2114E+05";
		numeros[4] = "-.3197E-01";
		numeros[5] = ".3574E+08";
		numeros[6] = ".3891E+08";
		numeros[7] = ".6158";
		numeros[8] = ".6420E+07";
		numeros[9] = "-.8783";
		numeros[10] = "0.000000E+00";
		numeros[11] = "0.9228";
		numeros[12] = "1.760";
		numeros[13] = "10.000000";
		numeros[14] = "110.000000";
		numeros[15] = "112.7";
		numeros[16] = "1311.";
		numeros[17] = "14.14";
		numeros[18] = "2.056";
		numeros[19] = "210.00000";
		numeros[20] = "239.0";
		numeros[21] = "2534.";
		numeros[22] = "271";
		numeros[23] = "33.9";
		numeros[24] = "353.0";
		numeros[25] = "37.4";
		numeros[26] = "39.353530";
		numeros[27] = "40.2";
		numeros[28] = "41.800000";
		numeros[29] = "42.3";
		numeros[30] = "46.07";
		numeros[31] = "5978.";
		numeros[32] = "6.670";
		numeros[33] = "68";
		numeros[34] = "7.000000";
		numeros[35] = "7.428";
	}
	
	public static void main(String[] args) {
		
		TesteFormataNumerosReais t = new TesteFormataNumerosReais();
		
		int n = 36;
		String numeros[] = new String[n];
		t.carregarNumeros(numeros);
		
		DecimalFormatSymbols dfs = new DecimalFormatSymbols ();  
		dfs.setGroupingSeparator ('.');  
		dfs.setDecimalSeparator (',');
		
		//DecimalFormat df = new DecimalFormat ("#,##0.00");
		DecimalFormat df = new DecimalFormat ("#,##0.00", dfs);
		
		for(int i=0; i < n; i++) {
			try {
				
				System.out.println("Original: " + numeros[i] + "\t\t Convertido: " + df.parse(numeros[i]).doubleValue());
				
			} catch (ParseException e) {
				
				System.out.println("Erro ao converter " + numeros[i]);
				e.printStackTrace();
				
			} 
		}  
		
	}
}

Saída do Código:

Original: .00000000		 Convertido: 0.0
Original: .1021E+05		 Convertido: 1021.0 // Desconsiderou a notação científica e não considerou o primeiro ponto
Original: -.2003E-01            Convertido: -200.3 
Original: .2114E+05		 Convertido: 2114.0  
Original: -.3197E-01		 Convertido: -319.7 
Original: .3574E+08		 Convertido: 3574.0 
Original: .3891E+08		 Convertido: 3891.0 
Original: .6158		 	 Convertido: 6158.0 
Original: .6420E+07		 Convertido: 6420.0 
Original: -.8783		 	 Convertido: -8783.0 
Original: 0.000000E+00	 Convertido: 0.0 
Original: 0.9228		 	 Convertido: 9228.0
Original: 1.760		 	 Convertido: 1760.0
Original: 10.000000	 	 Convertido: 1.0E7
Original: 110.000000	 	 Convertido: 1.1E8
Original: 112.7		 	 Convertido: 1127.0
Original: 1311.		 	 Convertido: 1311.0
Original: 14.14		 	 Convertido: 1414.0
Original: 2.056		 	 Convertido: 2056.0
Original: 210.00000	 	 Convertido: 2.1E7
Original: 239.0		 	 Convertido: 2390.0
Original: 2534.		 	 Convertido: 2534.0
Original: 271		 	 Convertido: 271.0
Original: 33.9		 	 Convertido: 339.0
Original: 353.0		 	 Convertido: 3530.0
Original: 37.4		 	 Convertido: 374.0
Original: 39.353530	 	 Convertido: 3.935353E7
Original: 40.2		 	 Convertido: 402.0
Original: 41.800000	 	 Convertido: 4.18E7
Original: 42.3		 	 Convertido: 423.0
Original: 46.07		 	 Convertido: 4607.0
Original: 5978.		 	 Convertido: 5978.0
Original: 6.670		 	 Convertido: 6670.0
Original: 68		 	 Convertido: 68.0 
Original: 7.000000		 Convertido: 7000000.0 
Original: 7.428		 	 Convertido: 7428.0 

No exemplo abaixo (TESTADO), tanto faz se foi utilizado PONTO ou VÍRGULA como separador decimal;
os valores STRING serão convertidos para DOUBLE.

        for(int i=0; i < 36; i++) {  
            String talNumero = numeros[i].replace(',', '.');
            System.out.println("Original: " + numeros[i] + "\t\t Convertido: " + Double.parseDouble(talNumero));   
        }     

[quote=Emersonsts]Oi Entanglement,

Criei uma classe de teste aqui, infelizmente o resultado não foi o esperado, um dos erros foi que ele não considerou notação científica e nem a notação ".59" para representar "0.59"

Coloquei algumas valores reais de teste, são valores gerados por programas em Fortran.
[/quote]

Hum, poderia ter posto um exemplo do que você queria. 99% das pessoas aqui querem algo pronto para resolver os problemas monetários; nem pensei que você estaria com um arquivo contendo números gerados por um programa Fortran. É que o pessoal que usa Pascal (Delphi) também chama de “número real” um double. Se você tivesse usado o jargão Fortran “DOUBLE PRECISION” eu já teria entendido logo de cara.

A conversão de números em notação científica é trivial em Java, porque você pode usar o velho e bom “Double.parseDouble()” para obter um double. O único problema é que Double.parseDouble exige que o separador seja um ponto, não uma vírgula.

Como o Marcio Lima apontou, já que você sabe de antemão que o separador é ponto ou vírgula, pode trocar ou não o separador.

Pessoal, muito obrigado, resolveu o meu problema. :slight_smile:

Só fui ver as respostas hoje.

O Double.parseDouble funcionou legal, mas é aquilo que comentaram: só funciona com separador decimal sendo ponto.

Vou deixar um código exemplo aqui para se alguém precisar um dia.

public class ConversaoNumerosFortran {

	public void carregarNumeros(String[] numeros) {

		numeros[0] = ".00000000";
		numeros[1] = ".1021E+05";
		numeros[2] = "-.2003E-01";
		numeros[3] = ".2114E+05";
		numeros[4] = "-.3197E-01";
		numeros[5] = ".3574E+08";
		numeros[6] = ".3891E+08";
		numeros[7] = ".6158";
		numeros[8] = ".6420E+07";
		numeros[9] = "-.8783";
		numeros[10] = "0.000000E+00";
		numeros[11] = "0.9228";
		numeros[12] = "1.760";
		numeros[13] = "10.000000";
		numeros[14] = "110.000000";
		numeros[15] = "112.7";
		numeros[16] = "1311.";
		numeros[17] = "14.14";
		numeros[18] = "2.056";
		numeros[19] = "210.00000";
		numeros[20] = "239.0";
		numeros[21] = "2534.";
		numeros[22] = "271";
		numeros[23] = "33.9";
		numeros[24] = "353.0";
		numeros[25] = "37.4";
		numeros[26] = "39.353530";
		numeros[27] = "40.2";
		numeros[28] = "41.800000";
		numeros[29] = "42.3";
		numeros[30] = "46.07";
		numeros[31] = "5978.";
		numeros[32] = "6.670";
		numeros[33] = "68";
		numeros[34] = "7.000000";
		numeros[35] = "7.428";
	}

	public static void main(String[] args) {

		ConversaoNumerosFortran t = new ConversaoNumerosFortran();

		int n = 36;
		String numerosPonto[] = new String[n];
		t.carregarNumeros(numerosPonto);
		
		// Teste do uso de replace
		String numerosVirgula[] = new String[n];
		
		System.out.println("\n\n--- Trocando ponto por vírgula para simular uma entrada diferente");
		for(int i=0;i&lt;n; i++) {
			numerosVirgula[i] = numerosPonto[i].replace('.', ',');
			System.out.println("Antes: " + numerosPonto[i]);
			System.out.println("Depois: " + numerosVirgula[i] + "\n");
		}
		
		System.out.println("\n--- Convertendo números com Double.parseDouble(). Separador decimal: '.'");
		for(int i=0;i&lt;n;i++) {
			System.out.println("Antes: " + numerosPonto[i]);
			System.out.println("Depois:" + Double.parseDouble(numerosPonto[i]) +"\n");
		}
		
		System.out.println("\n--- Convertendo números com Double.parseDouble(). Separador decimal: ','");
		for(int i=0;i&lt;n;i++) {
			System.out.println("Antes: " + numerosVirgula[i]);
			System.out.println("Depois:" + Double.parseDouble(numerosVirgula[i]) +"\n");
		}

	}
}

Saída:

--- Trocando ponto por vírgula para simular uma entrada diferente
Antes: .00000000
Depois: ,00000000

Antes: .1021E+05
Depois: ,1021E+05

Antes: -.2003E-01
Depois: -,2003E-01

Antes: .2114E+05
Depois: ,2114E+05

Antes: -.3197E-01
Depois: -,3197E-01

Antes: .3574E+08
Depois: ,3574E+08

Antes: .3891E+08
Depois: ,3891E+08

Antes: .6158
Depois: ,6158

Antes: .6420E+07
Depois: ,6420E+07

Antes: -.8783
Depois: -,8783

Antes: 0.000000E+00
Depois: 0,000000E+00

Antes: 0.9228
Depois: 0,9228

Antes: 1.760
Depois: 1,760

Antes: 10.000000
Depois: 10,000000

Antes: 110.000000
Depois: 110,000000

Antes: 112.7
Depois: 112,7

Antes: 1311.
Depois: 1311,

Antes: 14.14
Depois: 14,14

Antes: 2.056
Depois: 2,056

Antes: 210.00000
Depois: 210,00000

Antes: 239.0
Depois: 239,0

Antes: 2534.
Depois: 2534,

Antes: 271
Depois: 271

Antes: 33.9
Depois: 33,9

Antes: 353.0
Depois: 353,0

Antes: 37.4
Depois: 37,4

Antes: 39.353530
Depois: 39,353530

Antes: 40.2
Depois: 40,2

Antes: 41.800000
Depois: 41,800000

Antes: 42.3
Depois: 42,3

Antes: 46.07
Depois: 46,07

Antes: 5978.
Depois: 5978,

Antes: 6.670
Depois: 6,670

Antes: 68
Depois: 68

Antes: 7.000000
Depois: 7,000000

Antes: 7.428
Depois: 7,428


--- Convertendo números com Double.parseDouble(). Separador decimal: '.'
Antes: .00000000
Depois:0.0

Antes: .1021E+05
Depois:10210.0

Antes: -.2003E-01
Depois:-0.02003

Antes: .2114E+05
Depois:21140.0

Antes: -.3197E-01
Depois:-0.03197

Antes: .3574E+08
Depois:3.574E7

Antes: .3891E+08
Depois:3.891E7

Antes: .6158
Depois:0.6158

Antes: .6420E+07
Depois:6420000.0

Antes: -.8783
Depois:-0.8783

Antes: 0.000000E+00
Depois:0.0

Antes: 0.9228
Depois:0.9228

Antes: 1.760
Depois:1.76

Antes: 10.000000
Depois:10.0

Antes: 110.000000
Depois:110.0

Antes: 112.7
Depois:112.7

Antes: 1311.
Depois:1311.0

Antes: 14.14
Depois:14.14

Antes: 2.056
Depois:2.056

Antes: 210.00000
Depois:210.0

Antes: 239.0
Depois:239.0

Antes: 2534.
Depois:2534.0

Antes: 271
Depois:271.0

Antes: 33.9
Depois:33.9

Antes: 353.0
Depois:353.0

Antes: 37.4
Depois:37.4

Antes: 39.353530
Depois:39.35353

Antes: 40.2
Depois:40.2

Antes: 41.800000
Depois:41.8

Antes: 42.3
Depois:42.3

Antes: 46.07
Depois:46.07

Antes: 5978.
Depois:5978.0

Antes: 6.670
Depois:6.67

Antes: 68
Depois:68.0

Antes: 7.000000
Depois:7.0

Antes: 7.428
Depois:7.428


--- Convertendo números com Double.parseDouble(). Separador decimal: ','
Antes: ,00000000
Exception in thread "main" java.lang.NumberFormatException: For input string: ",00000000"
	at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
	at java.lang.Double.parseDouble(Unknown Source)
	at ConversaoNumerosFortran.main(ConversaoNumerosFortran.java:70)

>