Arredondamento ABNT (SAT)
Enviado: 21 Set 2016 09:08
Alguém fez a função de arredondamento ABNT 
Código: Selecionar todos
FUNCTION Round_ABNT(nValor,nDecimais)
LOCAL nRetorno:=nValor, cDecimais:=SubStr(Str(nValor),At('.',Str(nValor))+1), nSubsequente:=nDecimais+1
if nDecimais<1
RETURN Int(nRetorno)
endif
if Len(cDecimais) <= nDecimais
RETURN nRetorno
endif
if SubStr(cDecimais,nSubsequente,1)>'5' .or. SubStr(cDecimais,nSubsequente,1)<'5' //Se a casa decimal SUBSEQUENTE for DIFERENTE de 5
nRetorno:=Round(nValor,nDecimais) //ARREDONDA
elseif SubStr(cDecimais,nSubsequente,1)=='5' //Se a casa decimal SUBSEQUENTE for IGUAL a 5
if Mod(Val(SubStr(cDecimais,nDecimais,1)),2) <> 0 //Se a casa decimal que será CONSERVADA, for IMPAR
nRetorno:=Round(nValor,nDecimais) //ARREDONDA
else //se a casa decimal que será CONSERVADA, for PAR
if Val(SubStr(cDecimais,nSubsequente+1,1)) > 0 //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
nRetorno:=Round(nValor,nDecimais) //ARREDONDA
else //Se APÓS a casa decimal SUBSEQUENTE, não houver NENHUM outro algarismo ou TODOS forem iguais a ZERO
nRetorno:=Truncate(nValor,nDecimais) //TRUNCA (Esse é o único momento em que o "arredondamento ABNT" se diferencia do "arredondamento normal")
endif
endif
endif
RETURN nRetorno
FUNCTION Truncate(nValor,nDecimais)
LOCAL nRetorno:=nValor, cDecimais:=SubStr(Str(nValor),At('.',Str(nValor))+1)
if nDecimais<1
RETURN Int(nRetorno)
endif
if Len(cDecimais) <= nDecimais
RETURN nRetorno
endif
nRetorno:=Val( Str(Int(nValor))+'.'+SubStr(cDecimais,1,nDecimais) )
RETURN nRetorno
Código: Selecionar todos
*******************************************************************************
FUNCTION NewROUND(f_val,f_dec)
*******************************************************************************
local dig18
local dig19
local dig20
local valor
default f_dec := 2
if valtype(f_val) # "N"
return f_val
endif
valor := str(f_val,20,4)
if right(valor,2) != '00'
dig18 := substr(valor,18,1)
dig19 := substr(valor,19,1)
dig20 := substr(valor,20,1)
if dig19 == '5' .and. isPar(val(dig18))
if dig20 == '0'
valor := str(xround(f_val,f_dec),20,f_dec)
else
valor := str( round(f_val,f_dec),20,f_dec)
endif
else
valor := str( round(f_val,f_dec),20,f_dec)
endif
endif
return val(valor)
*******************************************************************************
FUNCTION isPar(VALOR)
*******************************************************************************
RETURN if( valor % 2 == 0,.t.,.f.)
Código: Selecionar todos
#include "FiveWin.ch" // I LOVE THIS
static oWnd
#xtranslate round(<nVal>,<nDec>) => val(str(<nVal>,20,<nDec>))
FUNCTION Main()
local oBar
DEFINE WINDOW oWnd TITLE "TestE Round() Harbour and xHarbour: Perfect!"
DEFINE BUTTONBAR oBar _3D OF oWnd
DEFINE BUTTON OF oBar ACTION Test_Round()
SET MESSAGE OF oWnd TO "TestE Round()" NOINSET CLOCK DATE KEYBOARD
ACTIVATE WINDOW oWnd
RETURN NIL
FUNCTION Test_Round()
LOCAL nImp, qt, preco, nNewImp, nNewValor
nNewValor := 0
nImp := 0.00
qt := 0.299
preco := 8.98
//nImp := Round( (qt * preco) , 2 )
nImp := ( ROUND( qt, 2 ) ) * ( ROUND( preco, 2 ) )
? ROUND( nImp, 2 )
? Str( Round( nImp, 2 ), 12, 6 ) // veja como apresenta aqui
nImp := Round(Val(StrZero(preco*qt,12,2)),4)
? ROUND( nImp, 2)
nNewImp := PADR( nImp, 6 )
nImp := VAL( PADR( nNewImp, 6 ) )
nNewValor := ROUND( nImp, 2 )
? nNewValor // assim retorna correto
RETURN NIL
Código: Selecionar todos
#include "extend.api"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#define SOMA 0
#define SUBTRACAO 1
#define MULTIPLICACAO 2
#define DIVISAO 3
#define PRECISAO 20
double par1, par2;
int decimal;
char result[21];
void do_oper(int oper)
{double r1, err;
int dec, sig, aux;
char err_c[PRECISAO+1];
strcpy(err_c, "0.");
aux = decimal;
while(aux != 0)
{strcat(err_c, "0");
aux--;
}
strcat(err_c, "1");
err = atof(err_c);
switch(oper)
{case SOMA:
r1 = par1 + par2;
break;
case SUBTRACAO:
r1 = par1 - par2;
break;
case MULTIPLICACAO:
r1 = (par1 * par2);
break;
case DIVISAO:
r1 = (par1 / par2);
break;
}
if(r1 > 0)
r1 += err;
else
r1 -= err;
strcpy(result, ecvt(r1, PRECISAO, &dec, &sig));
if(dec<1)
{char ret[PRECISAO+1];
if( ((sig!=0)&&(dec<2-PRECISAO)) || ((sig==0)&&(dec<1-PRECISAO)) || (dec<=-(decimal)) )
{strcpy(ret, "0.");
if(decimal>0)
{aux = decimal;
while(aux>0)
{strcat(ret, "0");
aux--;}
}
strcpy(result, ret);
}
else
{strcpy(ret, "0.");
aux = dec;
while(aux<0)
{strcat(ret, "0");
aux++;
}
strncat(ret, result, decimal+dec);
strcpy(result, ret);
if(sig!=0)
{strcpy(ret, "-");
strncat(ret, result, PRECISAO-1);
strcpy(result, ret);
}
}
}
else
{if( ((sig==0)&&(dec>PRECISAO)) || ((sig!=0)&&(dec>PRECISAO-1)) )
{strcpy(result, "*");
aux = PRECISAO-1;
while(aux>0)
{strcat(result, "*");
aux--;
}
}
else
{char ret1[PRECISAO+1], ret2[PRECISAO+1];
strcpy(ret1, "");
strncat(ret1, result, dec);
if((sig==0)&&(dec>(PRECISAO-2)) || ((sig!=0)&&(dec>(PRECISAO-3))))
strcpy(result, ret1);
else
{strcat(ret1, ".");
strcpy(ret2, " ");
strncat(ret2, result, PRECISAO-1);
memmove(ret2, ret1, dec+1);
strcpy(result, "");
strncat(result, ret2, dec+1+decimal);
}
if(sig!=0)
{strcpy(ret1, "-");
strncat(ret1, result, PRECISAO-1);
strcpy(result, ret1);
}
}
}
return;
}
HB_FUNC (C_SUM)
{if(HB_ISCHAR(1))
par1 = atof(_parc(1));
else
par1 = _parnd(1);
if(HB_ISCHAR(2))
par2 = atof(_parc(2));
else
par2 = _parnd(2);
if(PCOUNT == 3)
{decimal = _parni(3);
if(decimal > 10)
decimal = 10;
else if(decimal < 0)
decimal = 0;
}
else
decimal = 2;
do_oper(SOMA);
_retc(result);}
HB_FUNC (C_SUB)
{if(HB_ISCHAR(1))
par1 = atof(_parc(1));
else
par1 = _parnd(1);
if(HB_ISCHAR(2))
par2 = atof(_parc(2));
else
par2 = _parnd(2);
if(PCOUNT == 3)
{decimal = _parni(3);
if(decimal > 10)
decimal = 10;
else if(decimal < 0)
decimal = 0;
}
else
decimal = 2;
do_oper(SUBTRACAO);
_retc(result);}
HB_FUNC (C_MULT)
{if(HB_ISCHAR(1))
par1 = atof(_parc(1));
else
par1 = _parnd(1);
if(HB_ISCHAR(2))
par2 = atof(_parc(2));
else
par2 = _parnd(2);
if(PCOUNT == 3)
{decimal = _parni(3);
if(decimal > 10)
decimal = 10;
else if(decimal < 0)
decimal = 0;
}
else
decimal = 2;
do_oper(MULTIPLICACAO);
_retc(result);}
HB_FUNC ( C_DIV )
{if(HB_ISCHAR(1))
par1 = atof(_parc(1));
else
par1 = _parnd(1);
if(HB_ISCHAR(2))
par2 = atof(_parc(2));
else
par2 = _parnd(2);
if(par2==0)
{printf("Erro de divisao por zero!");
exit(0);
}
else
{if(PCOUNT == 3)
{decimal = _parni(3);
if(decimal > 10)
decimal = 10;
else if(decimal < 0)
decimal = 0;
}
else
decimal = 2;
do_oper(DIVISAO);
_retc(result);
}
}
Código: Selecionar todos
Function Main()
Local nValorItem := 0.299
Local nQuantidade := 8.98
? Round( ( nValorItem * nQuantidade ), 2 ) // retorna 2.69
Return NilCódigo: Selecionar todos
*******************************************************************************
FUNCTION Round_ABNT(nValor,nDecimais)
*******************************************************************************
LOCAL nRetorno := nValor
LOCAL cDecimais := SubStr(Str(nValor),At('.',Str(nValor))+1)
LOCAL nSubsequente:= nDecimais+1
if nDecimais<1
RETURN Int(nRetorno)
endif
if Len(cDecimais) <= nDecimais
RETURN nRetorno
endif
if SubStr(cDecimais,nSubsequente,1)>'5' .or. SubStr(cDecimais,nSubsequente,1)<'5' //Se a casa decimal SUBSEQUENTE for DIFERENTE de 5
nRetorno:=nRound(nValor,nDecimais) //ARREDONDA
elseif SubStr(cDecimais,nSubsequente,1)=='5' //Se a casa decimal SUBSEQUENTE for IGUAL a 5
if Mod(Val(SubStr(cDecimais,nDecimais,1)),2) <> 0 //Se a casa decimal que será CONSERVADA, for IMPAR
nRetorno:=nRound(nValor,nDecimais) //ARREDONDA
else
// if Val(SubStr(cDecimais,nSubsequente+1,1)) > 0 //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
if Val(SubStr(cDecimais,nSubsequente+1)) > 0 //Se APÓS a casa decimal SUBSEQUENTE, houver ALGUM algarismo MAIOR que ZERO
nRetorno:=nRound(nValor,nDecimais) //ARREDONDA
else //Se APÓS a casa decimal SUBSEQUENTE, não houver NENHUM outro algarismo ou TODOS forem iguais a ZERO
nRetorno:=Truncate(nValor,nDecimais) //TRUNCA (Esse é o único momento em que o "arredondamento ABNT" se diferencia do "arredondamento normal")
endif
endif
endif
RETURN nRetorno


rs... Pois é. Em se tratando de aplicativo fiscal então nem se fala...asimoes escreveu:Essa regra de arredondamento é muito esquisita, enfim no brasil as coisas são estranhas mesmo.
Não entendi essa parte. o SAT não faz arredondamento nenhum, ele apenas verifica se os valores da soma dos itens estão corretos com o valor total do cupom, e se a forma de pagamento foi com valor igual ou superior a soma do cupom.luiz53 escreveu:todos eles fizeram o arredondamento ABNT igual esta na IMAGEM..