A transparência referencial pode ser assumida quando se lida com aritmética de ponto flutuante?

5

Presume-se que uma função pura produza as mesmas saídas dadas as mesmas entradas. Suponha que uma função livre de efeitos colaterais (de outra forma) seja computada com números de ponto flutuante. Devido a erros numéricos, essas saídas podem ser diferentes (dependendo do sistema, do paralelismo, das otimizações do compilador ...) Por exemplo . Então, tecnicamente, a função não é referencialmente transparente.

Um problema diferente, mas relacionado, é quando definimos um monóide de adição sobre números de ponto flutuante. O principal pressuposto subjacente, em FP, é de associatividade de adição, que é violada sob precisão finita: cf. link para um exemplo básico.

Existe alguma relevância prática de tais violações para a programação funcional? Se não, deveríamos simplesmente assumir a transparência referencial? Ou deveríamos lutar pelo TR máximo, por exemplo, escolhendo uma linguagem com melhor reprodutibilidade de resultados numéricos à custa de sua precisão?

    
por Tupolev._ 31.01.2018 / 15:21
fonte

3 respostas

3

Is there any practical relevance of such violations to functional programming?

Acho que você deixou claro que a resposta é "sim".

If not, should we simply assume referential transparency?

A única maneira de ver isso sendo OK é se a única coisa que importa é saber se os resultados são aproximadamente os mesmos. Mas isso tem grandes armadilhas, pois pequenas inconsistências podem se tornar muito maiores quando a multiplicação e a divisão estão envolvidas.

Or should we strive for maximal RT, eg, by choosing a language with better reproducibility of numerical results at the expense of their precision?

Eu não acho que você precise reduzir a precisão. O que eliminaria esses problemas é usar um tipo que evita usar frações binárias para tentar fazer matemática com números em outra base (e / ou não possui toda a estranheza histórica do ponto flutuante). Um tipo com precisão decimal infinita funciona como um tipo com precisão decimal fixa. Se você quiser que ele ocupe o mesmo espaço que os tipos de ponto flutuante, talvez seja necessário sacrificar alguma precisão.

    
por 31.01.2018 / 18:03
fonte
2

Tudo depende da qualidade de sua implementação (e às vezes a implementação terá que abrir mão da velocidade para preservar as propriedades da implementação que você deseja).

Em C, C ++, etc., exatamente a mesma declaração sobre a mesma implementação poderia dar resultados diferentes. Por exemplo, em um loop, todas as iterações pares podem calcular um resultado de uma maneira e todas as iterações ímpares podem calculá-lo de outra maneira. Esse é o caso mais extremo. Menos extremo: o mesmo código em locais diferentes pode dar resultados diferentes. O mesmo código em duas execuções diferentes do programa pode dar resultados diferentes. O mesmo código em duas implementações diferentes pode fornecer resultados diferentes. Eu diria que apenas o caso mais extremo - a mesma afirmação dando resultados diferentes - seria um problema no que diz respeito à sua pergunta.

Se isso acontecer, você deve estar sob controle da sua implementação. Mas o exemplo que você deu (duas implementações dando resultados diferentes) não é um problema (bem, é um problema, mas completamente não relacionado à transparência referencial). Sua implementação só tem que garantir que no mesmo programa executado, executando o mesmo código com os mesmos dados uma vez, várias vezes, atrasado, o que for, sempre dará o mesmo resultado. Mesmo tendo duas funções diferentes que devem dar os mesmos resultados, mas não, não é um problema a esse respeito.

É claro que sua linguagem é livre para definir a aritmética de ponto flutuante de uma maneira que dá menos liberdade à implementação e o problema desaparece.

    
por 04.02.2018 / 18:24
fonte
1

A violação da transparência referencial é um problema se você construir sobre ela. Pode-se construir sobre isso apenas raciocinando sobre uma função, e nesse raciocínio realmente usando a propriedade RT. Sentir a partir do seu texto: eu acho: no local onde a transparência referencial é violada [pela subespecificação do cálculo do ponto flutuante] [por exemplo comunicação entre computadores]: você nem mesmo aplica programação funcional. Todo o sistema de software não precisa ser expresso de maneira funcional para aproveitar os benefícios da programação funcional. Com outras palavras: a aplicação da programação funcional pode ser parcial e ainda ser enormemente benéfica. A programação funcional não é um paradigma (tudo ou nada), mas sim (quanto mais, melhor).

Você se preocupa com a violação de algumas propriedades algébricas por operações de ponto flutuante. Essa questão não está strongmente relacionada à programação funcional, pois o raciocínio algébrico e a programação funcional podem ser praticados sem o outro.

Mas a preocupação ainda é válida. Essas propriedades algébricas se baseiam em uma função de igualdade no tipo de número. Se esse teste de igualdade for definido pelo IEEE [o padrão na maioria dos ambientes de programação], a soma do número de ponto flutuante não é associativa, portanto, o tipo não pode implementar verdadeiramente uma interface Semigroup. Mas é possível envolver esse tipo de número em um tipo de envelope "Aproximado", elevar a função de soma do tipo de número bruto ao nível de Aproximado e fornecer uma função de teste de igualdade aproximada para Aproximada [retornaria true constantemente]. Então Aproximado pode implementar o Semigrupo no sentido algébrico estrito. Essa seria uma prática de codificação baseada em princípios, mas alguns engenheiros de software preferem, em algumas situações, não se submeter ao aborrecimento prático, e apenas lembrar que a implementação do Semigroup dos tipos de número de ponto flutuante bruto deve ser interpretada em um sentido aproximado.

    
por 03.02.2018 / 21:50
fonte