Como efetuar operações de ponto flutuante com MIDP 2.0 e CLDC 1.1

Boa tarde!
Estou tentando efetuar operações de ponto flutuante com double, para efetuar cálculos com moeda.
No entanto, sempre ocorre uma imprecisão indesejável de 0.01 para mais (ou para menos).
Gostaria de saber como posso contornar isso para que os cálculos com moeda sejam precisos. Já procurei a classe BigDecimal, mas parece que ela não existe para Java em dispositivos móveis…

Já tentou [color=blue]long[/color]?

Não tentei…como eu posso usar long para efetuar cálculos com ponto flutuante?
Como faço essa utilização?

Não…não tentei ainda. Como utilizo long para efetuar operações com ponto flutuante?

O que ele lhe sugeriu é fazer as contas em centavos (ou em décimos de centavos). Dá um pouco de trabalho…

Porque vc não usa double?

double numero1 = 6.5;
double numero2 = 66.7;
double numero3 = numero1 / numero2;

Bem, eu faria as operações utilizando ints ou longs com o valor em centavos.

Outra alternativa é copiar e colar a classe BigDecimal e mudar o pacote.

Pra que copiar classe BigDecimal, e fazer o cauculo em centavos se pode-se usar double? Pra que inventar se já está pronto?

A classe BigDecimal é imensa; não vai caber em um dispositivo limitado.

Quanto a efetuar o cálculo com centavos, entendi mais ou menos…
o problema é que vou fazer diversos tipos de cálculo, não somente soma, mas multiplicação, divisão…é aí que acho que complica utilizar long na parte inteira e fracionária…vou ter que simular esses tipos, talvez “precisar” onde a vírgula vai cair…passar um valor do cálculo de centavos para a parte inteira…

O tipo Double eu já estava utilizando. Como expliquei no início do tópico, ele apresenta imprecisão no cálculo de operações com moeda…fica dando uma diferença muito pequena para cima e para baixo.

A classe BigDecimal eu teria que pegar do Math e readaptá-la né?

Em centavos converteria:
R$1,59 = 159 centavos…
Eu faço as operações e uso um método para converter de volta para Double?

Quer dizer que se vc fizer:

double n1 = 3.51;
double n2 = n1 * 2;

O resultado em n2 não será 7,02???

[quote=npereirajr]Porque vc não usa double?

double numero1 = 6.5;
double numero2 = 66.7;
double numero3 = numero1 / numero2;[/quote]

Porque float e double sofrem com erros de arredondamentos que se traduzem em um grande desastre em cálculos financeiros.

[quote=thingol][quote]
Outra alternativa é copiar e colar a classe BigDecimal e mudar o pacote.
[/quote]
A classe BigDecimal é imensa; não vai caber em um dispositivo limitado. [/quote]

E se for copiado apenas o mínimo necessário? Tipo, os métodos que não são utilizados dela não precisam vir junto.

[quote=diego_qmota]Em centavos converteria:
R$1,59 = 159 centavos…
Eu faço as operações e uso um método para converter de volta para Double?[/quote]

Para que converter em double? Esqueça o double e simplesmente não o use em lugar algum! Deixe sempre-sempre-sempre em centavos. Apenas na hora de mostrar para o usuário você enfia a vírgula lá, trabalhando com String:

public String mostrarValor(int valorEmCentavos) { return "R$ " + String.valueOf(valorEmCentavos / 100) + "," + String.valueOf(valorEmCentavos % 100); }

Hum… como a divisão nunca dá resultado exato, então é necessário sempre fazer algumas adaptações.

Digamos que você tenha 1234 centavos e precise dividir isso por 3. Isso vai dar 411 (OK). Obviamente 411 * 3 = 1233, mas isso é esperado.

Mas nem sempre a vida lhe dá multiplicações e divisões fáceis. Nesse caso você precisa ver se em MIDP2/CLDC1.1 existem aquelas operações de arredondamento (Math.rint, Math.round). Por exemplo, digamos que você precise multiplicar 1234 centavos por 1.00234 (cálculo de algum juro).

1234 * 1.00234 = 1236.88756

No seu caso, você quer o resultado 1237 (que é o arredondamento correto). Você então deve usar Math.round, que recebe um double, arredonda-o (usando “Banker’s rounding”), e retorna 1237 (long).

Eu realizo cálculos em double… que nessa versão de mip já suporta, depois eu montei um método de arredontamento… já que o double trabalha com mais casas decimais, dando diferença somente nas últimas … o método de arredondamento funciona certinho e retira as casas sobressalentes deixando somente as duas últimas para exibição…

[quote]Porque vc não usa double?

double numero1 = 6.5;
double numero2 = 66.7;
double numero3 = numero1 / numero2;[/quote]

Nesse caso não dá diferença, mas eu estou utilizando uma classe que criei para efetuar operação de potenciação.
Nessa operação (por exemplo):

Java (tipo Double): 230 * (1,005 elevado a 1) = 231.14999999…
Calculadora: 230 * (1,005 elevado a 1) = 231.15

Neste caso não uso o elevado a 1, mas em vários casos elevo a potências maiores (para calcular juros compostos, por exemplo).
É daí que resulta a imprecisão que o usuário pode reclamar…

public String mostrarValor(int valorEmCentavos) { return "R$ " + String.valueOf(valorEmCentavos / 100) + "," + String.valueOf(valorEmCentavos % 100); }

Compreendi a idéia…mas não dá o problema relatado abaixo?
Como é feito o arrendodamento? de 0.5 pra cima = 1 ou de 0.5 para baixo = 0.0?
Eu procurei e não encontrei o Math.round para o Midp. Aliás os métodos disponíveis dessas classes são bem limitados e em pequeno número…

[quote=diego_qmota]public String mostrarValor(int valorEmCentavos) { return "R$ " + String.valueOf(valorEmCentavos / 100) + "," + String.valueOf(valorEmCentavos % 100); }

Compreendi a idéia…mas não dá o problema relatado abaixo?
Como é feito o arrendodamento? de 0.5 pra cima = 1 ou de 0.5 para baixo = 0.0?
Eu procurei e não encontrei o Math.round para o Midp. Aliás os métodos disponíveis dessas classes são bem limitados e em pequeno número…

[/quote]

O truque é você trabalhar em unidades cada vez menores até que tudo que você tenha sejam unidades inteiras, o que elimina qualquer necessidade de arredondamento ou de tratamento de frações. Se centavos não é o suficiente, use décimos de centavos, centésimos de centavos, e assim por diante.

Mas, dependendo das operações que você fizer, isso não funciona. Neste caso, vale tentar criar alguma imitação de BigDecimal ou uma classe que represente um número racional (algo que tenha os atributos numerador e denominador).