Arredondamento de Valor. Onde?

13/05/2008

2

Pessoal, tenho o seguinte codigo:

ValorIncompleto := QtdeParcelas * DuasCasasDecimais(DMEntradaNota.CdsEntradaNota.FieldByName(´VALORNOTA´).AsFloat / QtdeParcelas);

Resto := DMEntradaNota.CdsEntradaNota.FieldByName(´VALORNOTA´).AsFloat - ValorIncompleto;

Este código é responsável por ´acertar´ o valor total de uma certa nota pois,
sem este código, o delphi fazia o arredondamento, e quando por exemplo
o valor da nota era de R$ 1,00 e este valor fosse dividido em 3 parcelas,
aparecia para o usuário 3 parcelas de R$ 0,33.

Logo, total das parcelas ficava, R$ 0,99.

{ Não preciso falar da importância de R$ 0,01 num fechamento de caixa por exemplo... }

este código estava fluindo bem, fazendo a somatório do resto na última parcela, até que eu inseri para teste, os seguintes valores:

VALORNOTA: R$ 9,78
QTDEPARCELAS: 3

Não entendi o porque, ou onde está havendo o arredondamento, mas com estes valores o delphi retorna o seguinte resultado:

1ª Parcela: 3,26
2ª Parcela: 3,26
3ª Parcela: 3,29

Com os testes descobri que o delphi faz a seguinte conta e com o seguinte resultado:

9,78 / 3 = 3,25 {Os valores são exatos como estes mesmo}

Logo, 3 * 3,25 = R$ 9,75
Logo, R$ 9,78 - R$ 9,75 = R$ 0,03 <---- RESTO

Nisso, ele soma esses R$ 0,03 na ultima parcela, totalizando o valor da nota como R$ 9,81

A FIM DE ESCLARECIMENTO: função DuasCasasDecimais:
function DuasCasasDecimais(valor : real) : real;
begin
result := Trunc(Valor * 100) / 100;
end;


Se alguém poder me ajudar, por favor.

agradeço.


Responder

Posts

13/05/2008

Marco Salles

amigo não sei se entend ibem o que voce quer mas veja a diferença
entre as duas funçoes abaixo..


function DuasCasasDecimais(valor : real) : real; begin result := Trunc(Valor * 100) / 100; end;


function DuasCasasDecimaisExtended(valor :extended) : extended;
begin
result := Trunc(Valor * 100) / 100;
end;


showmessage(floattostr(DuasCasasDecimais(9.78)));
showmessage(floattostr(DuasCasasDecimaisExtended(9.78)));


como se trata de arredondamento usar Extended pode fornecer resultados mais precisos...


Responder

14/05/2008

Webjoel

Olá!

Você não precisa usar esta função que você criou, o delphi já tem uma própria.

Ex:

valorParcela := RoundTo(VALOR,-2); //neste caso vai arredondar para duas casas decimais, mas você pode trocar o "-2" por outro número dependndo do arredondamento desejado.



Responder

14/05/2008

Rb2228

Salles,
alterei a função e utilizei o extended, e alterei as variáveis ValorIncompleto e Resto tbm. Não funcionou.

Simplificando: Tenho o valor total da nota, o usuário insere a qtde de parcelas. Tenho uma rotina que divide o valor total em parcelas e mostro as parcelas, cada qual com o seu respectivo valor num grid.

O problema é que no grid, é mostrado apenas duas casas após a vírgula, e eu calculo a soma das parcelas para comparar com o valor total da nota.
Como no grid é mostrado apenas duas casas após a virgula, o que de fato nao esta incorreto pois se trata de dinheiro, imagine os seguintes valores:

Valor total da nota: R$ 100,00 Qtde Parcelas: 3
Valores no grid:
1ª Parcela: 33,33
2ª Parcela: 33,33
3ª Parcela: 33,33

Total: 99,99 <------- Ficou faltando R$ 0,01 para chegar no R$ 100,00.

Então tenho a rotina postada no topico para me retornar o valor que falta para completar, e somo esse valor na ultima parcela, assim:

1ª Parcela: 33,33
2ª Parcela: 33,33
3ª Parcela: 33,34

Total: 100,00 <------- Valor correto.

PROBLEMA: Com estes valores: Valor Nota: R$ 9,78 Qtde Parcelas: 3
não da certo pois o delphi insiste em que 9,78 / 3 resulta em 3,25.

e mostra os seguintes valores:

1ª Parcela: 3,26
2ª Parcela: 3,26
3ª Parcela: 3,29

Total: 9,81 <------- Ficou sobrando R$ 0,03


simplifiquei ou confundi mais ainda?

obrigado.


Responder

14/05/2008

Rb2228

Webjoel, eu utilizo a função DuasCasasDeciamais para truncar o valor, e não arredondar. De qualquer modo, obrigado.


Responder

14/05/2008

Edilcimar

Por que você não pega o valor total, subtrai das parcelas anteriores, o resto será automaticamente o valor da última prestação
Ex: ValorTotal := 100, Parcela1 = 100/3, Parcela2 = 100/3 e Parcela3 = ValorTotal - Parcela1 - Parcela2


Responder

14/05/2008

Marco Salles

Amigo , fiz aqui rapidinho com o ClientDataSet em Memoria e não obtive nenhum problema

function DuasCasasDecimaisExtended(valor :extended) : extended;
begin
result := Trunc(Valor * 100) / 100;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
t,r,s:extended;
i,n:integer;

begin
t:=strtofloat(edit1.text);
n:=strtoint(edit2.text);
s:=0;
r:=DuasCasasDecimaisExtended(t/n);
for i:=1 to n-1 do
begin
cds.Append;
cds.FieldByName(´valorEmReal´).AsFloat:=r;
cds.FieldByName(´ValorEmCurrency´).AsFloat:=r;
cds.Post;
s:=s+r;
end;
s:=t-s;
cds.Append;
cds.FieldByName(´r´).AsFloat:=s;
cds.FieldByName(´c´).AsFloat:=s;
cds.FieldByName(´e´).AsFloat:=s;
cds.Post;

end;


Se Deu certo comigo provavelmente vai dar certo com voce...


Responder

14/05/2008

Rb2228

Salles,
não sei se concorda, mas o Edilcimar tem razão. uma forma mais simplificada de se fazer.

mas o problema ainda persiste pois, o delphi não esta fazendo os cálculos corretamente.

estou com o seguinte codigo agora:

If (i = QtdeParcelas) Then DMEntradaNota.CdsPagamentoNota.FieldByName(´CDPNVALORPARCELA´).AsFloat := DMEntradaNota.CdsEntradaNota.FieldByName(´CDENVALORNOTA´).AsFloat - (QtdeParcelas - 1) * (DuasCasasDecimais(DMEntradaNota.CdsEntradaNota.FieldByName(´CDENVALORNOTA´).AsFloat / QtdeParcelas))
Else                                        
  DMEntradaNota.CdsPagamentoNota.FieldByName(´CDPNVALORPARCELA´).AsFloat := DMEntradaNota.CdsEntradaNota.FieldByName(´CDENVALORNOTA´).AsFloat / QtdeParcelas;


com os mesmos valores o erro ainda persiste. :? [/code]


Responder

14/05/2008

Marco Salles

Salles, não sei se concorda, mas o Edilcimar tem razão. uma forma mais simplificada de se fazer.


edicilmar escreveu:
Por que você não pega o valor total, subtrai das parcelas anteriores, o resto será automaticamente o valor da última prestação Ex: ValorTotal := 100, Parcela1 = 100/3, Parcela2 = 100/3 e Parcela3 = ValorTotal - Parcela1 - Parcela2


Mas foi [b:55dd9ecb13]exatamente[/b:55dd9ecb13] o que lhe apresentei no ultimo post , com o exemplo do clientDataSet

function DuasCasasDecimaisExtended(valor :extended) : extended; 
begin 
result := Trunc(Valor * 100) / 100; 
end;



procedure TForm1.Button1Click(Sender: TObject); 
var 
ValorTotal,parcela,Soma:extended; 
i,n:integer; 

begin 
ValorTotal:=strtofloat(edit1.text); 
n:=strtoint(edit2.text);  //Numerod e parcelas
Soma:=0; 
Parcela:=DuasCasasDecimaisExtended(t/n); 
for i:=1 to n-1 do 
begin
cds.Append; 
cds.FieldByName(´valorEmReal´).AsFloat:=r; 
cds.Post; 
//Como é um comando For .. as PArcelas1 + Parcelas2+parcelas3 etc...
//São somadas a Variável Soma
soma:=Soma+parcela; 
end; 
//A Variavel Soma contem o Valor da Ultima Parcela ,
Soma:=ValorTotal - Soma; 
cds.Append; 
cds.FieldByName(´ValorReal´).AsFloat:=Soma;  
cds.Post; 
end;



Responder

14/05/2008

Rb2228

If (i = QtdeParcelas) Then
                                        {DuasCasasDecimais, é uma função criada que trunca o valor em duas casas após a vírgula}
                                        DMEntradaNota.CdsPagamentoNota.FieldByName(´CDPNVALORPARCELA´).AsFloat     := DMEntradaNota.CdsEntradaNota.FieldByName(´CDENVALORNOTA´).AsFloat - varSomaParcelas
                                   {Se nao for a ultima parcela}
                                   Else
                                   begin
                                        DMEntradaNota.CdsPagamentoNota.FieldByName(´CDPNVALORPARCELA´).AsFloat     := DMEntradaNota.CdsEntradaNota.FieldByName(´CDENVALORNOTA´).AsFloat / QtdeParcelas;
                                        varSomaParcelas := varSomaParcelas + DMEntradaNota.CdsPagamentoNota.FieldByName(´CDPNVALORPARCELA´).AsFloat;
                                   end;


Perfeito! Deu certo... tanto com valores inteiros como quebrados.

Salles, me desculpe, não havia entendido muito bem no post anterior

mas agora sim, Obrigado!


Responder

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários. Para saber mais sobre o uso de cookies,
consulte nossa política de privacidade. Ao continuar navegando em nosso site, você concorda com a nossa política.

Aceitar