Arredondamento
Abrangência
Todas as versões |
Quando utilizado o tipo numérico do AdvPL, pode haver diferença de arredondamento em algumas operações aritméticas. Isso ocorre devido ao armazenamento numérico do AdvPL ser baseado em ponto flutuante usado pelo Protheus. Estas diferenças inclusive, estão presentes no AdvPL, mesmo antes do surgimento do Protheus.
A representação de um número em ponto flutuante na memória está sujeita a aproximação de valores. Mesmo um valor inteiro ou com apenas dois dígitos decimais, pode ser representada internamente por um número fracionário aproximado. Isto significa que, um número resultante de uma operação aritmética entre dois números pode gerar um valor aproximado em memória que é diferente da representação deste terceiro número. Estas diferenças normalmente são perceptíveis nas operações de comparação numérica.
Para garantir o comportamento correto nas comparações, devemos utilizar uma das funções de ajuste de precisão decimal ( Round() e/ou NoRound() ), onde informamos o número e a quantidade de casas decimais de ajuste para este número. Enquanto a função Round() arredonda o número caso a próxima casa decimal posterior a informada seja igual ou maior que 5, a função NoRound() "corta" o número sem arredondar. Por exemplo, Round(3.1415,3) = 3.142 e NoRound(3.1415,3) = 3.141
Exemplos:
Ao invés de ...... If (nValor/30) >= 0.01
Utilize ........... If Round(nValor/30, 2) >= 0.01
ou ................ If NoRound(nValor/30, 2) >= 0.01
Explicação:
Uma operação aritmética qualquer, mesmo uma soma ou subtração entre dois números, pode gerar internamente um valor aproximado menor ou maior do que o valor real a ser representado. Por exemplo, um número como 2938.68, ao ser armazenado na memória como um ponto flutuante, internamente terá o valor aproximado de 2938.6799999999998 – que na prática é apenas 0.0000000000002 menor que 2938.68 – enquanto o número 2938.67 pode ser representado como 2938.6700000000001 – que tem apenas 0.0000000000001 a mais que o número original ... Quando fazemos uma operação aritmética de subtração entre eles ( o maior menos o menor ) , o resultado também será aproximado – Ao invés de ser 0.01 ( que é realmente a diferença entre 2938.68 e 2938.67 ), o resultado da operação usando os dois valores aproximados pode ser menor que 0.01 – por exemplo 0.0099999999997635314. A diferença deste valor para 0,01 é apenas 0,0000000000002364686 – que é irrelevante para uma operação aritmética e dois valores com apenas duas casas decimais significativas. Mas sem o ajuste de arredondamento, este número representado na memória não é maior ou igual a 0.01
As operações numéricas de igualdade e comparação consideram irrelevantes diferenças menores que 0,00000005 (5e-08), e caso seja utilizada uma precisão mais agressiva – usando por exemplo a configuração FloatingPointPrecise, qualquer diferença até a 15a casa decimal é considerada na comparação numérica. Por isso a utilização das funções de arredondamento nas comparações numéricas entre valores calculados informando a precisão em uso ou desejada é fundamental para o correto funcionamento das aplicações.