O que pode ser feito com linguagens de programação para evitar armadilhas de ponto flutuante?

28

O mal-entendido da aritmética de ponto flutuante e suas falhas é uma das principais causas de surpresa e confusão na programação (considere o número de perguntas no Stack Overflow referentes a "números que não são adicionados corretamente"). Considerando que muitos programadores ainda não entenderam suas implicações, ele tem o potencial de introduzir muitos erros sutis (especialmente no software financeiro). O que pode linguagens de programação fazer para evitar suas armadilhas para aqueles que não estão familiarizados com os conceitos, enquanto continua a oferecer a sua velocidade quando a precisão não é crítica para aqueles que fazem compreender os conceitos?

Adam Paynter
fonte
26
A única coisa que uma linguagem de programação pode fazer para evitar as armadilhas do processamento de ponto flutuante é bani-la. Observe que isso inclui também o ponto flutuante de base 10, que é tão impreciso em geral, exceto que os aplicativos financeiros são pré-adaptados a ele.
David Thornley 28/03
4
É para isso que serve "Análise Numérica". Aprenda a minimizar a perda de precisão - também conhecidas como armadilhas de ponto flutuante.
Um bom exemplo de uma questão de ponto flutuante: stackoverflow.com/questions/10303762/0-0-0-0-0
Austin Henley

Respostas:

47

Você diz "especialmente para software financeiro", o que traz à tona um dos meus ódios de estimação: dinheiro não é uma bóia, é um int .

Claro, parece um carro alegórico. Tem um ponto decimal lá. Mas isso é apenas porque você está acostumado a unidades que confundem o problema. O dinheiro sempre vem em quantidades inteiras. Na América, é centavos. (Em certos contextos, acho que podem ser moinhos , mas ignore isso por enquanto.)

Então, quando você diz US $ 1,23, são 123 centavos. Sempre, sempre, sempre faça suas contas nesses termos, e você ficará bem. Para mais informações, veja:

Respondendo à pergunta diretamente, as linguagens de programação devem incluir apenas um tipo Money como uma primitiva razoável.

atualizar

Ok, eu deveria ter dito "sempre" duas vezes, em vez de três. O dinheiro é realmente sempre um int; quem pensa de outra forma é bem-vindo a tentar me enviar 0,3 centavos e me mostrar o resultado em seu extrato bancário. Mas, como os comentaristas apontam, há raras exceções quando você precisa fazer matemática de ponto flutuante em números do tipo dinheiro. Por exemplo, certos tipos de preços ou cálculos de juros. Mesmo assim, esses devem ser tratados como exceções. O dinheiro entra e sai como quantidades inteiras; portanto, quanto mais próximo o sistema estiver disso, mais saudável será.

William Pietri
fonte
20
@ JoelFan: você está confundindo um conceito com uma implementação específica de plataforma.
Whatsisname
12
Não é tão simples assim. Cálculos de juros, entre outros, produzem centavos fracionários e precisam ser arredondados em algum momento, de acordo com um método especificado.
precisa
24
Ficcional -1, já que eu não tenho o representante para um voto negativo :) ... Isso pode estar correto para o que quer que esteja na sua carteira, mas há muitas situações contábeis nas quais você pode estar lidando com décimos de centavo ou frações menores. Decimalé o único sistema sensato para lidar com isso, e seu comentário "ignora isso por enquanto" é o prenúncio de desgraça para programadores em todos os lugares: P
detly
9
@ Kevin Cline: Existem centavos fracionários nos cálculos, mas existem convenções sobre como lidar com eles. O objetivo dos cálculos financeiros não é a correção matemática, mas a obtenção dos mesmos resultados que um banqueiro com uma calculadora obteria.
David Thornley 29/03
6
Tudo será perfeito, substituindo a palavra "inteiro" com "racional" -
Emilio Garavaglia
15

Fornecer suporte para um tipo decimal ajuda em muitos casos. Muitos idiomas têm um tipo decimal, mas são subutilizados.

É importante compreender a aproximação que ocorre quando se trabalha com representação de números reais. Usar os tipos de ponto decimal e de ponto flutuante 9 * (1/9) != 1é uma afirmação correta. Quando constantes, um otimizador pode otimizar o cálculo para que esteja correto.

Fornecer um operador aproximado ajudaria. No entanto, essas comparações são problemáticas. Observe que 0,9999 trilhão de dólares é aproximadamente igual a 1 trilhão de dólares. Você poderia depositar a diferença na minha conta bancária?

BillThor
fonte
2
0.9999...trilhão de dólares é exatamente igual a 1 trilhão de dólares.
APENAS MINHA OPINIÃO correta
5
@ APENAS: Sim, mas não encontrei nenhum computador com registros que aguentem 0.99999.... Todos eles truncam em algum momento, resultando em uma desigualdade. 0.9999é igual o suficiente para a engenharia. Para fins financeiros, não é.
BillThor
2
Mas que tipo de sistema usou trilhões de dólares como unidade base em vez de dólares?
Brad
@Brad Tente calcular (1 trilhão / 3) * 3 na sua calculadora. Que valor você recebe?
BillThor
8

Fomos informados sobre o que fazer no primeiro ano (no segundo ano) da aula de ciências da computação quando eu fui para a universidade (este curso também era um pré-requisito para a maioria dos cursos de ciências)

Lembro-me do palestrante dizendo "Números de ponto flutuante são aproximações. Use tipos inteiros por dinheiro. Use FORTRAN ou outro idioma com números BCD para obter um cálculo preciso". (e depois apontou a aproximação, usando o exemplo clássico de 0,2 impossível de representar com precisão no ponto flutuante binário). Isso também apareceu naquela semana nos exercícios de laboratório.

A mesma palestra: "Se você precisar obter mais precisão do ponto flutuante, classifique seus termos. Adicione números pequenos, não grandes." Isso ficou na minha mente.

Alguns anos atrás, eu tinha uma geometria esférica que precisava ser muito precisa e ainda rápida. O dobro de 80 bits nos PCs não estava diminuindo, então eu adicionei alguns tipos ao programa que classificavam os termos antes de executar operações comutativas. Problema resolvido.

Antes de reclamar da qualidade do violão, aprenda a tocar.

Eu tinha um colega de trabalho há quatro anos que trabalhava na JPL. Ele expressou descrença de que usamos FORTRAN para algumas coisas. (Precisávamos de simulações numéricas super precisas calculadas off-line.) "Substituímos todo esse FORTRAN por C ++", disse ele, orgulhoso. Parei de me perguntar por que eles perderam um planeta.

Tim Williscroft
fonte
2
Marque com +1 a ferramenta certa para o trabalho certo. Embora eu realmente não use FORTRAN. Felizmente, nem trabalho em nossos sistemas financeiros no trabalho.
James Khoury
"Se você precisar obter mais precisão do ponto flutuante, classifique seus termos. Adicione números pequenos, não grandes." Alguma amostra disso?
mamcx
@mamcx Imagine um número de ponto flutuante decimal com apenas um dígito de precissão. O cálculo 1.0 + 0.1 + ... + 0.1(repetido 10 vezes) retorna à 1.0medida que cada resultado intermediário é arredondado. Fazê-lo de outra maneira, você obtém resultados intermediários de 0.2, 0.3, ..., 1.0e, finalmente 2.0. Este é um exemplo extremo, mas com números de ponto flutuante realistas, problemas semelhantes acontecem. A idéia básica é que a adição de números semelhantes em tamanho leve ao menor erro. Comece com os números menores, pois sua soma é maior e, portanto, mais adequada para adição a números maiores.
Maaartinus
As coisas de ponto flutuante no Fortran e C ++ serão praticamente idênticas. Ambos são precisos e off-line, e eu tenho certeza que Fortran não tem reais BCD nativos ...
Mark
8

Aviso: O tipo de ponto flutuante System.Double não possui a precisão para testes diretos de igualdade.

double x = CalculateX();
if (x == 0.1)
{
    // ............
}

Não acredito que algo possa ou deva ser feito no nível do idioma.

ChaosPandion
fonte
1
Não uso boia ou dobra há muito tempo, por isso estou curioso. Esse é um aviso do compilador existente ou apenas um que você gostaria de ver?
Karl Bielefeldt
1
@Karl - Pessoalmente, eu não vi ou preciso, mas imagino que poderia ser útil para desenvolvedores dedicados, mas ecológicos.
ChaosPandion
1
Os tipos de ponto flutuante binário não são nem melhores nem piores qualitativamente do que Decimalquando se trata de teste de igualdade. A diferença entre 1.0m/7.0m*7.0me 1.0mpode ser muitas ordens de magnitude menor que a diferença entre 1.0/7.0*7.0, mas não é zero.
30812
1
@ Patrick - Eu não tenho certeza do que você está chegando. Há uma enorme diferença entre algo verdadeiro para um caso e verdadeiro para todos os casos.
precisa saber é o seguinte
1
@ChaosPandion O problema com o exemplo neste post não é a comparação de igualdade, é o literal de ponto flutuante. Não há flutuação com o valor exato 1.0 / 10. A matemática de ponto flutuante resulta em resultados 100% precisos ao computar com números inteiros dentro da mantissa.
Patrick
7

Por padrão, os idiomas devem usar argumentos de precisão arbitrária para números não inteiros.

Quem precisa otimizar pode sempre pedir carros alegóricos. Usá-los como padrão fazia sentido em C e outras linguagens de programação de sistemas, mas não na maioria dos idiomas populares atualmente.

Waquo
fonte
1
Como você lida com números irracionais então?
dsimcha
3
Você faz da mesma maneira que com carros alegóricos: aproximação.
Waquo 28/03
1
Eu tenho que dizer que acho que isso faz muito sentido, a maioria das pessoas que precisa de números exatos precisa de racionais, não de irracionais (ciência e engenharia podem usar irracionais, mas você volta ao domínio aproximado novamente ou está fazendo algumas matemáticas puras bastante especializadas)
jk.
1
Computações com racionalidades de precisão arbitrária geralmente serão ordens de magnitude mais lenta (possivelmente MUITAS ordens de magnitude mais lentas) do que as computações com suporte de hardware double. Se um cálculo precisa ser preciso com uma parte por milhão, é melhor gastar um microssegundo calculando-o dentro de algumas partes por bilhão, do que gastar um segundo calculando-o com precisão absoluta.
Supercat 01/08
5
@supercat: O que você está sugerindo é apenas um filho da otimização prematura. A situação atual é que a grande maioria dos programadores não precisa de matemática rápida e, em seguida, é mordida por difícil compreensão do comportamento de ponto flutuante (mis), de modo que o número relativamente pequeno de programadores que precisam de matemática rápida o obtenha sem ter para digitar um único caractere extra. Isso fazia sentido nos anos setenta, agora é apenas um absurdo. O padrão deve ser seguro. Quem precisa de jejum deve pedir.
Waquo 01/08/19
4

Os dois maiores problemas envolvendo números de ponto flutuante são:

  • unidades inconsistentes aplicadas aos cálculos (observe que isso também afeta a aritmética inteira da mesma maneira)
  • falha em entender que os números FP são uma aproximação e como lidar de forma inteligente com o arredondamento.

O primeiro tipo de falha pode ser solucionado apenas fornecendo um tipo composto que inclui informações de valor e unidade. Por exemplo, um lengthou areavalor que incorpora a unidade (metros ou metros quadrados ou pés e pés quadrados, respectivamente). Caso contrário, você deve ser diligente em trabalhar sempre com um tipo de unidade de medida e somente converter em outro quando compartilharmos a resposta com um ser humano.

O segundo tipo de falha é uma falha conceitual. As falhas se manifestam quando as pessoas as consideram como números absolutos . Isso afeta operações de igualdade, erros cumulativos de arredondamento etc. Por exemplo, pode ser correto que, para um sistema, duas medições sejam equivalentes dentro de uma certa margem de erro. Ou seja, .999 e 1.001 são aproximadamente os mesmos que 1.0 quando você não se importa com diferenças menores que +/- .1. No entanto, nem todos os sistemas são tão brandos.

Se houver alguma facilidade no nível do idioma, eu chamaria isso de precisão da igualdade . Nas estruturas de teste NUnit, JUnit e de construção semelhante, é possível controlar a precisão considerada correta. Por exemplo:

Assert.That(.999, Is.EqualTo(1.001).Within(10).Percent);
// -- or --
Assert.That(.999, Is.EqualTo(1.001).Within(.1));

Se, por exemplo, C # ou Java foram alterados para incluir um operador de precisão, pode ser algo como isto:

if(.999 == 1.001 within .1) { /* do something */ }

No entanto, se você fornecer um recurso como esse, também deverá considerar o caso em que a igualdade é boa se os lados +/- não forem os mesmos. Por exemplo, + 1 / -10 consideraria dois números equivalentes se um deles estivesse dentro de 1 a mais ou 10 a menos que o primeiro número. Para lidar com esse caso, pode ser necessário adicionar uma rangepalavra - chave:

if(.999 == 1.001 within range(.001, -.1)) { /* do something */ }
Berin Loritsch
fonte
2
Eu trocaria a ordem. O problema conceitual é generalizado. O problema de conversão de unidades é relativamente pequeno em comparação.
31511 S.Lott
Gosto do conceito de operador de precisão, mas, como você mencionou mais adiante, definitivamente precisaria ser bem pensado. Pessoalmente, eu estaria mais inclinado a vê-lo como sua própria construção sintática completa.
ChaosPandion
Também poderia ser feito com muita facilidade em uma biblioteca.
Michael K
1
@ dan04: Eu estava pensando mais em termos de "todos os cálculos precisos até um por cento" ou algo parecido. Eu vi o poço de alcatrão que é a unidade de medida e estou ficando longe.
TMN
1
Há cerca de 25 anos, vi um pacote numérico com um tipo que consiste em um par de números de ponto flutuante representando os valores máximos e mínimos possíveis para uma quantidade. À medida que os números passavam pelos cálculos, a diferença entre o máximo e o mínimo aumentava. Efetivamente, isso forneceu um meio de saber quanta precisão real estava presente em um valor calculado.
30812
3

O que as linguagens de programação podem fazer? Não sei se há uma resposta para essa pergunta, porque qualquer coisa que o compilador / intérprete faça em nome do programador para facilitar sua vida geralmente funciona contra desempenho, clareza e legibilidade. Eu acho que tanto a maneira C ++ (pague apenas pelo que você precisa) quanto a maneira Perl (princípio da menor surpresa) são válidas, mas depende da aplicação.

Os programadores ainda precisam trabalhar com a linguagem e entender como ela lida com pontos flutuantes, porque, se não o fizerem, farão suposições, e um dia o comportamento perscrutado não corresponderá às suposições.

Minha opinião sobre o que o programador precisa saber:

  • Quais tipos de ponto flutuante estão disponíveis no sistema e no idioma
  • Que tipo é necessário
  • Como expressar as intenções de que tipo é necessário no código
  • Como aproveitar corretamente qualquer promoção automática de tipo para equilibrar clareza e eficiência, mantendo a correção
John
fonte
3

O que as linguagens de programação podem fazer para evitar armadilhas [de ponto flutuante] ...?

Use padrões sensíveis, por exemplo, suporte embutido para decimais.

O Groovy faz isso muito bem, embora com um pouco de esforço você ainda possa escrever código para introduzir a imprecisão de ponto flutuante.

Armand
fonte
3

Concordo que não há nada a fazer no nível do idioma. Os programadores devem entender que os computadores são discretos e limitados e que muitos dos conceitos matemáticos representados neles são apenas aproximações.

Não importa o ponto flutuante. É preciso entender que metade dos padrões de bits são usados ​​para números negativos e que 2 ^ 64 é realmente muito pequeno para evitar problemas típicos com aritmética inteira.

Apalala
fonte
discordo, a maioria dos idiomas atualmente oferece suporte demais para tipos de ponto flutuante binário (por que == é definido mesmo para flutuadores?) e não oferece suporte suficiente para argumentos racionais ou decimais
jk.
@jk: Mesmo que o resultado de qualquer cálculo nunca seja garantido igual ao resultado de qualquer outro cálculo, a comparação de igualdade ainda seria útil no caso em que o mesmo valor seja atribuído a duas variáveis ​​(embora as regras de igualdade comumente implementadas sejam talvez muito frouxo, pois x== ynão implica que a execução de uma computação ativada xproduzirá o mesmo resultado que a execução da mesma computação ativada y).
Supercat 01/08
@ supercat você ainda precisa de comparação, mas eu prefiro que a linguagem exigisse que eu especificasse uma tolerância para cada comparação de ponto flutuante. Ainda posso voltar à igualdade escolhendo tolerance = 0, mas sou pelo menos forçado a fazer isso. escolha
jk.
3

Uma coisa que os idiomas podem fazer - remover a comparação de igualdade dos tipos de ponto flutuante que não seja uma comparação direta com os valores da NAN.

O teste de igualdade só existiria como uma chamada de função que levou os dois valores e um delta, ou para idiomas como C # que permitem que os tipos tenham métodos um EqualsTo que leva o outro valor e o delta.

Loren Pechtel
fonte
3

Acho estranho que ninguém tenha apontado o truque numérico racional da família Lisp.

Sério, abra o sbcl e faça o seguinte: (+ 1 3)e você recebe 4. Se *( 3 2)você obtém 6. Agora tente (/ 5 3)e você obtém 5/3 ou 5 terços.

Isso deve ajudar um pouco em algumas situações, não deveria?

Haakon Løtveit
fonte
Gostaria de saber se possível saber se um resultado precisa ser representado como 1/3 ou pode ser um decimal exato?
mamcx
boa sugestão #
611 Peter Porfy
3

Uma coisa que eu gostaria de ver seria um reconhecimento de que doublea floatdeve ser considerado como uma conversão alargando, ao mesmo tempo floatque doubleestá a diminuir (*). Isso pode parecer contra-intuitivo, mas considere o que os tipos realmente significam:

  • 0.1f significa "13.421.773,5 / 134.217.728, mais ou menos 1 / 268.435.456 ou mais".
  • 0.1 significa realmente 3.602.879.701.896.397 / 36.028.797.018.963.968, mais ou menos 1 / 72.057.594.037.927.936 ou mais "

Se alguém possui um doubleque detém a melhor representação da quantidade "um décimo" e a converte float, o resultado será "13.421.773,5 / 134.217.728, mais ou menos 1 / 268.435.456 ou mais", que é uma descrição correta do valor.

Por outro lado, se alguém possui um floatque mantém a melhor representação da quantidade "um décimo" e a converte double, o resultado será "13.421.773,5 / 134.217.728, mais ou menos 1 / 72.057.594.037.927.936 ou mais" - um nível de precisão implícita o que está errado por um fator de mais de 53 milhões.

Embora o padrão IEEE-744 exija que a matemática de ponto flutuante seja executada como se todo número de ponto flutuante represente a quantidade numérica exata precisamente no centro de seu intervalo, isso não deve ser considerado como implicando que os valores de ponto flutuante realmente representem os valores exatos quantidades numéricas. Em vez disso, o requisito de que os valores sejam considerados no centro de seus intervalos decorre de três fatos: (1) os cálculos devem ser realizados como se os operandos tivessem alguns valores precisos específicos; (2) suposições consistentes e documentadas são mais úteis que as inconsistentes ou não documentadas; (3) se alguém fizer uma suposição consistente, nenhuma outra suposição consistente será melhor do que assumir que uma quantidade representa o centro de seu intervalo.

Aliás, lembro-me de cerca de 25 anos atrás, alguém inventou um pacote numérico para C que usava "tipos de intervalo", cada um consistindo em um par de flutuadores de 128 bits; todos os cálculos seriam feitos de maneira a calcular o valor mínimo e máximo possível para cada resultado. Se alguém executasse um grande cálculo iterativo longo e obtivesse um valor de [12.53401391134 12.53902812673], pode-se ter certeza de que, embora muitos dígitos de precisão tenham sido perdidos por erros de arredondamento, o resultado ainda pode ser razoavelmente expresso como 12,54 (e não foi '' realmente 12,9 ou 53,2). Estou surpreso por não ter visto nenhum suporte para esses tipos em nenhum idioma convencional, especialmente porque eles parecem se encaixar em unidades matemáticas que podem operar com vários valores em paralelo.

(*) Na prática, geralmente é útil usar valores de precisão dupla para armazenar cálculos intermediários ao trabalhar com números de precisão única; portanto, ter que usar uma conversão de tipo para todas essas operações pode ser irritante. Os idiomas poderiam ajudar por ter um tipo "duplo difuso", que executaria os cálculos em dobro e poderia ser convertido livremente para e do único; isso seria especialmente útil se as funções que recebem parâmetros de tipo doublee retorno doublepudessem ser marcadas para gerar automaticamente uma sobrecarga que aceita e retorna "fuzzy double".

supercat
fonte
2

Se mais linguagens de programação tirassem uma página dos bancos de dados e permitissem aos desenvolvedores especificar o comprimento e a precisão de seus tipos de dados numéricos, eles poderiam reduzir substancialmente a probabilidade de erros relacionados a pontos flutuantes. Se um idioma permitisse que um desenvolvedor declarasse uma variável como Flutuante (2), indicando que eles precisavam de um número de ponto flutuante com dois dígitos decimais de precisão, ele poderia executar operações matemáticas com muito mais segurança. Se o fizesse representando a variável como um inteiro internamente e dividindo por 100 antes de expor o valor, poderia melhorar a velocidade usando os caminhos aritméticos inteiros mais rápidos. A semântica de um Float (2) também permitiria que os desenvolvedores evitassem a constante necessidade de arredondar os dados antes de enviá-los, uma vez que um Float (2) arredondaria os dados inerentemente para duas casas decimais.

Obviamente, você precisa permitir que um desenvolvedor solicite um valor de ponto flutuante de precisão máxima quando o desenvolvedor precisar dessa precisão. E você apresentaria problemas nos quais expressões ligeiramente diferentes da mesma operação matemática produzem resultados potencialmente diferentes devido às operações de arredondamento intermediário quando os desenvolvedores não possuem precisão suficiente em suas variáveis. Mas, pelo menos no mundo dos bancos de dados, isso não parece grande coisa. A maioria das pessoas não está fazendo os tipos de cálculos científicos que exigem muita precisão em resultados intermediários.

Justin Cave
fonte
Especificar comprimento e precisão faria muito pouco útil. Ter uma base de ponto fixo 10 seria útil para o processamento financeiro, o que removeria grande parte das surpresas que as pessoas recebem do ponto flutuante.
David Thornley 28/03
@ David - Talvez eu esteja faltando alguma coisa, mas como é um tipo de dados de base 10 de ponto fixo diferente do que estou propondo aqui? Um ponto flutuante (2) no meu exemplo teria dois dígitos decimais fixos e arredondaria automaticamente para o centésimo mais próximo, o que você provavelmente usaria para cálculos financeiros simples. Cálculos mais complexos exigiriam que o desenvolvedor alocasse um número maior de dígitos decimais.
Justin Caverna
1
O que você está defendendo é um tipo de dados de base 10 de ponto fixo com precisão especificada pelo programador. Estou dizendo que a precisão especificada pelo programador é praticamente inútil e levará apenas aos tipos de erros que eu costumava encontrar nos programas COBOL. (Por exemplo, quando você alterar a precisão de variáveis, é real fácil perder uma variável o valor atravessa Por outro lado, vai demorar muito mais a pensar sobre o tamanho do resultado intermediário do que é bom..)
David Thornley
4
Um Float(2)como você propõe não deve ser chamado Float, pois não há nada flutuando aqui, certamente não o "ponto decimal".
Paŭlo Ebermann 28/03
1
  • os idiomas têm suporte ao tipo decimal; é claro que isso realmente não resolve o problema, ainda assim você não tem uma representação exata e finita de, por exemplo ⅓;
  • alguns bancos de dados e estruturas têm suporte ao tipo Money, basicamente armazenando o número de centavos como inteiro;
  • existem algumas bibliotecas para suporte a números racionais; que resolve o problema de ⅓, mas não resolve o problema de, por exemplo, √2;

Os itens acima são aplicáveis ​​em alguns casos, mas não são realmente uma solução geral para lidar com valores flutuantes. A solução real é entender o problema e aprender a lidar com ele. Se você estiver usando cálculos de ponto flutuante, sempre verifique se seus algoritmos são numericamente estáveis . Há um enorme campo de matemática / ciência da computação que se relaciona com o problema. Chama-se Análise Numérica .

vartec
fonte
1

Como outras respostas observaram, a única maneira real de evitar armadilhas de ponto flutuante no software financeiro é não usá-lo lá. Isso pode ser realmente viável - se você fornecer uma biblioteca bem projetada, dedicada à matemática financeira .

As funções projetadas para importar estimativas de ponto flutuante devem ser claramente rotuladas como tal e fornecidas com parâmetros apropriados para essa operação, por exemplo:

Finance.importEstimate(float value, Finance roundingStep)

A única maneira real de evitar armadilhas de ponto flutuante em geral é a educação - os programadores precisam ler e entender algo como o que todo programador deve saber sobre aritmética de ponto flutuante .

Algumas coisas que podem ajudar, no entanto:

  • Em segundo lugar, quem pergunta "por que o teste exato de igualdade para ponto flutuante é legal?"
  • Em vez disso, use uma isNear()função.
  • Forneça e incentive o uso de objetos acumuladores de ponto flutuante (que adicionam seqüências de valores de ponto flutuante de maneira mais estável do que simplesmente adicioná-los todos a uma variável regular de ponto flutuante).
tempestade
fonte
-1

Muitos programadores ficariam surpresos com o fato de o COBOL acertar ... na primeira versão do COBOL, não havia ponto flutuante, apenas decimal, e a tradição no COBOL continuou até hoje em que a primeira coisa que você pensa ao declarar um número é decimal. .. ponto flutuante só seria usado se você realmente precisasse. Quando C apareceu, por algum motivo, não havia um tipo decimal primitivo; portanto, na minha opinião, foi aí que todos os problemas começaram.

JoelFan
fonte
1
C não tinha um tipo decimal porque não é primitivo, muito poucos computadores possuem instruções decimais de hardware. Você pode perguntar por que o BASIC e o Pascal não o possuíam, pois eles não foram projetados para se adaptarem muito ao metal. COBOL e PL / I são os únicos idiomas que conheço da época que tinham algo parecido.
David Thornley 28/03
3
@JoelFan: então como você escreve ⅓ em COBOL? Não Decimal não resolver todos os problemas, base 10 é tão imprecisa como base 2.
vartec
2
Decimal resolve o problema de representar exatamente dólares e centavos, o que é útil para um idioma "orientado para negócios". Mas, caso contrário, o decimal é inútil; possui os mesmos tipos de erros (por exemplo, 1/3 * 3 = 0.99999999), sendo muito mais lento. Que é por isso que é não o padrão em idiomas que não foram projetados especificamente para a contabilidade.
Dan04 29/03
1
E o FORTRAN, que antecede C há mais de uma década, também não tem suporte decimal padrão.
dan04
1
@ JoelFan: se você tem valor trimestral e precisa de valor por mês, adivinhe o que você precisa para multiplicá-lo por ... não, não é 0,33, é ⅓.
vartec 29/03