it-swarm-pt.tech

Use Flutuante ou Decimal para o Valor do Dólar da Aplicação Contábil?

Estamos reescrevendo nosso sistema de contabilidade herdado no VB.NET e no SQL Server. Trouxemos uma nova equipe de programadores .NET/SQL para fazer a reescrita. A maior parte do sistema já está concluída com os valores em dólares usando Floats. A linguagem do sistema legado, eu programei, não tinha um Float então eu provavelmente teria usado um Decimal.

Qual a sua recomendação?

O tipo de dados flutuante ou decimal deve ser usado para valores em dólar?

Quais são alguns dos prós e contras de qualquer um deles?

Um Con mencionado em nosso scrum diário foi que você tem que ter cuidado ao calcular um valor que retorna um resultado que é mais de duas posições decimais. Parece que você terá que arredondar o valor para duas posições decimais.

Outro Con é todos os displays e os valores impressos precisam ter uma declaração de formato que mostre duas posições decimais. Eu notei algumas vezes onde isso não foi feito e as quantidades não pareciam corretas. (isto é, 10,2 ou 10,2546)

Um pro é o Float ocupa apenas 8 bytes no disco onde o Decimal ocuparia 9 bytes (Decimal 12,2) 

74
Gerhard Weiss
41
Nakilon

Primeiro você deve ler isto O que todo cientista da computação deve saber sobre aritmética de ponto flutuante . Então você deve realmente considerar o uso de algum tipo de ponto fixo/número de precisão arbitrária package (por exemplo, Java BigNum, módulo decimal python), caso contrário você estará em um mundo de dor. Em seguida, descubra se o uso do tipo decimal SQL nativo é suficiente. 

Existem floats/duplas (ed) para expor o fast x87 fp que agora está praticamente obsoleto. Não os use se você se importar com a precisão dos cálculos e/ou não compensar totalmente suas limitações.

22
Rich Schuler

Assim como um aviso adicional, o SQL Server e a estrutura .Net usam um algoritmo padrão diferente para arredondamento. Certifique-se de verificar o parâmetro MidPointRounding em Math.Round (). O framework .NET usa o algoritmo Bankers por padrão e o SQL Server usa o arredondamento algorítmico simétrico. Confira o artigo da Wikipedia aqui

10
Darrel Miller

Pergunte aos seus contadores! Eles vão desaprovar você por usar float. Como alguém postou antes, use o float APENAS se você não se importar com a precisão. Embora eu sempre seria contra quando se trata de dinheiro.

No software de contabilidade não é aceitável um float. Use decimal com 4 pontos decimais.

7
Ricardo C

Pontos flutuantes têm números irracionais inesperados.

Por exemplo, você não pode armazenar 1/3 como um decimal, seria 0.3333333333 ... (e assim por diante)

Flutuadores são realmente armazenados como um valor binário e um poder de 2 expoente.

Então 1,5 é armazenado como 3 x 2 para -1 (ou 3/2)

Usando esses expoentes da base 2 criam alguns números irracionais estranhos, por exemplo:

Converter 1.1 para um float e, em seguida, convertê-lo novamente, o resultado será algo como: 1.0999999999989

Isso ocorre porque a representação binária de 1.1 é, na verdade, 154811237190861 x 2 ^ -47, mais do que um duplo pode manipular.

Mais sobre esta questão em meu blog , mas basicamente, para armazenamento, você é melhor com decimais.

No Microsoft SQL Server, você tem o tipo de dados money - isso geralmente é melhor para armazenamento financeiro. É preciso para 4 posições decimais.

Para os cálculos, você tem mais problemas - a imprecisão é uma pequena fração, mas é colocada em uma função de energia e rapidamente se torna significativa. 

No entanto decimais não são muito bons para qualquer tipo de matemática - não há suporte nativo para poderes decimais, por exemplo.

6
Keith

Um pouco de fundo aqui ....

Nenhum sistema numérico pode lidar com todos os números reais com precisão. Todos têm suas limitações, e isso inclui tanto o ponto flutuante IEEE padrão quanto o decimal sinalizado. O ponto flutuante do IEEE é mais preciso por bit usado, mas isso não importa aqui.

Os números financeiros são baseados em séculos de prática de papel e caneta, com convenções associadas. Eles são razoavelmente precisos, mas, mais importante, são reproduzíveis. Dois contadores trabalhando com vários números e taxas devem chegar ao mesmo número. Qualquer espaço para discrepância é espaço para fraudes.

Portanto, para cálculos financeiros, a resposta certa é o que dá a mesma resposta de um CPA que é bom em aritmética. Esta é a aritmética decimal, não o ponto flutuante IEEE.

5
David Thornley

Use o tipo decimal do SQL server.

Não use money ou float.

o dinheiro usa 4 casas decimais, é mais rápido que usar decimal MAS sofre de alguns problemas óbvios e alguns não tão óbvios com arredondamento ( veja este problema de conexão

5
Mitch Wheat

O que eu recomendo é usar números inteiros de 64 bits que armazenam a coisa toda em centavos.

5
Joshua

Flutuadores não são representações exatas, problemas de precisão são possíveis, por exemplo, ao adicionar valores muito grandes e muito pequenos. É por isso que os tipos decimais são recomendados para moeda, mesmo que o problema de precisão seja suficientemente raro.

Para esclarecer, o tipo decimal 12,2 armazenará esses 14 dígitos exatamente, enquanto o float não utilizará uma representação binária internamente. Por exemplo, 0,01 não pode ser representado exatamente por um número de ponto flutuante - a representação mais próxima é, na verdade, 0,0099999998

4
Niall

Para um sistema bancário que ajudei a desenvolver, fui responsável pela parte de "juros acumulados" do sistema. Cada dia, meu código calculava quanto interesse tinha sido acumulado (earnt) no saldo naquele dia.

Para esse cálculo, precisão extrema e fidelidade foram necessárias (usamos o FLOAT da Oracle) para registrarmos o "bilionésimo de um centavo" acumulado.

Quando se trata de "capitalizar" os juros (ou seja, pagar os juros de volta à sua conta), a quantia foi arredondada para a moeda de um centavo. O tipo de dados para os saldos das contas era de duas casas decimais. (Na verdade, foi mais complicado, pois era um sistema multi-moeda que poderia funcionar em muitas casas decimais - mas sempre arredondamos para o "centavo" dessa moeda). Sim - lá onde "frações" de perda e ganho, mas quando os números de computadores foram atualizados (dinheiro pago ou pago) sempre foram valores reais de dinheiro.

Isso satisfez os contadores, auditores e testadores.

Então, verifique com seus clientes. Eles lhe dirão suas regras e práticas bancárias/contábeis.

4
Guy

A única razão para usar o Float por dinheiro é se você não se importa com respostas precisas. 

4
David Singer

Outra coisa que você deve estar ciente nos sistemas de contabilidade é que ninguém deve ter acesso direto às tabelas. Isso significa que todo acesso ao sistema contábil deve ser feito por meio de procedimentos armazenados. Isso evita fraudes e não apenas ataques de injeção de SQL. Um usuário interno que deseja cometer fraude não deve ter a capacidade de alterar diretamente os dados nas tabelas de banco de dados, nunca. Este é um controle interno crítico em seu sistema. Você realmente quer que algum funcionário insatisfeito vá ao back-end de seu banco de dados e comece a processá-lo? Ou ocultar que eles aprovaram uma despesa para um fornecedor não autorizado quando não têm autoridade de aprovação? Apenas duas pessoas em toda a sua organização devem poder acessar diretamente os dados em seu banco de dados financeiro, seu dba e seu backup. Se você tiver muitos dbas, apenas dois deles devem ter esse acesso.

Menciono isso porque, se seus programadores usaram float em um sistema contábil, provavelmente não estão familiarizados com a ideia de controles internos e não os consideraram em seu esforço de programação.

3
HLGEM

Ainda melhor do que usar decimais é usar apenas inteiros antigos (ou talvez algum tipo de bigint). Desta forma, você sempre tem a maior precisão possível, mas a precisão pode ser especificada. Por exemplo, o número 100 poderia significar 1.00, que é formatado assim:

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

Se você gosta de ter mais precisão, você pode mudar o 100 para um valor maior, como: 10 ^ n, onde n é o número de decimais.

3
Peter Stuifzand

Das 100 frações n/100, onde n é um número natural tal que 0 <= n e n <100, somente quatro podem ser representados como números de ponto flutuante. Dê uma olhada na saída deste programa C:

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}
2
Lars Bohl

Você sempre pode escrever algo como um tipo de dinheiro para .net.

Dê uma olhada neste artigo: Um tipo de dinheiro para o CLR - O autor fez um excelente trabalho na minha opinião.

2
Tomer Pintel

Eu estava usando o tipo de dinheiro do SQL para armazenar valores monetários. Recentemente, tive que trabalhar com vários sistemas de pagamento on-line e notei que alguns deles usam números inteiros para armazenar valores monetários. Nos meus projetos atuais e novos, comecei a usar números inteiros e estou bastante satisfeito com essa solução.

2
George

Você provavelmente desejará usar alguma forma de representação de ponto fixo para valores monetários. Você também vai querer investigar o arredondamento de Banker (também conhecido como "round half even"). Isso evita distorções que existem no método "round up" usual.

1
user6931

Você já pensou em usar o tipo de dados monetários para armazenar valores em dólar?

Em relação ao Con que decimal ocupa mais um byte, eu diria que não se importam com isso. Em 1 milhão de linhas, você só usará mais 1 MB e o armazenamento é muito barato hoje em dia.

1
Espo

Faça o que fizer, você precisa ter cuidado com os erros de arredondamento. Calcule usando um maior grau de precisão do que você exibe em.

1
1800 INFORMATION

Seus contadores vão querer controlar como você ronda. Usar float significa que você estará constantemente arredondando, geralmente com uma instrução FORMAT (), que não é a maneira que você quer fazer (use floor/ceiling).

Você tem tipos de dados de moeda (money, smallmoney), que devem ser usados ​​em vez de float ou real. Armazenar decimal (12,2) eliminará seus arredondamentos, mas também os eliminará durante etapas intermediárias - o que realmente não é o que você desejará de forma alguma em um aplicativo financeiro.

0
David T. Macknet

Este é um excelente artigo descrevendo quando usar float e decimal . O Float armazena um valor aproximado e o decimal armazena um valor exato.

Em resumo, valores exatos como dinheiro devem usar valores decimais, e valores aproximados como medições científicas devem usar float. 

Aqui está um exemplo interessante que mostra que float e decimal são capazes de perder precisão. Ao adicionar um número que não é um inteiro e, em seguida, subtrair esse mesmo número, resulta na perda de precisão, enquanto o decimal não:

    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15

Ao multiplicar um não inteiro e dividir pelo mesmo número, os decimais perdem precisão, enquanto os floats não.

DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900
0
BrokeMyLegBiking

Sempre use decimal. Float lhe dará valores imprecisos devido a problemas de arredondamento.

0
Roel Vlemmings

Os números de ponto flutuante podem somente representar números que são uma soma de múltiplos negativos da base - para ponto flutuante binário, é claro, são dois.

Existem apenas quatro frações decimais representáveis ​​precisamente no ponto flutuante binário: 0, 0,25, 0,5 e 0,75. Tudo o resto é uma aproximação, da mesma forma que 0.3333 ... é uma aproximação para 1/3 na aritmética decimal.

O ponto flutuante é uma boa escolha para cálculos onde a escala do resultado é o que é importante. É uma má escolha quando você está tentando ser preciso em algumas casas decimais.

0
Mike Dimmick