Implementando divisão de precisão simples como multiplicação de precisão dupla
Para um compilador C99 implementando a aritmética IEEE 754 exata, façaf
, divisor
do tipofloat
existem tais quef / divisor != (float)(f * (1.0 / divisor))
?
EDIT: Por "implementação exata IEEE 754 aritmética" refiro-me a um compilador que legitimamente define FLT_EVAL_METHOD como 0.
ContextoUm compilador C que fornece ponto flutuante compatível com IEEE 754 só pode substituir uma divisão de precisão simples por uma constante por uma multiplicação de precisão simples pelo inverso se o inverso for ele próprio representável exatamente como umfloat
.
Na prática, isso só acontece com poderes de dois. Então, um programador, Alex, pode estar confiante de quef / 2.0f
será compilado como se tivesse sidof * 0.5f
, mas se é aceitável para Alex multiplicar por0.10f
em vez de dividir por 10, Alex deve expressá-lo escrevendo a multiplicação no programa, ou usando uma opção de compilador como o GCC-ffast-math
.
Esta questão é sobre transformar uma divisão de precisão única em uma multiplicação de precisão dupla. Produz sempre o resultado corretamente arredondado? Existe uma chance de que poderia ser mais barato e, portanto, uma otimização que os compiladores podem fazer (mesmo sem-ffast-math
)
Eu comparei(float)(f * 0.10)
ef / 10.0f
para todos os valores de precisão simplesf
entre 1 e 2, sem encontrar qualquer contra-exemplo. Isto deve cobrir todas as divisões defloat
s produzindo um resultado normal.
Então eu generalizei o teste para todos os divisores com o programa abaixo:
#include <float.h>
#include <math.h>
#include <stdio.h>
int main(void){
for (float divisor = 1.0; divisor != 2.0; divisor = nextafterf(divisor, 2.0))
{
double factor = 1.0 / divisor; // double-precision inverse
for (float f = 1.0; f != 2.0; f = nextafterf(f, 2.0))
{
float cr = f / divisor;
float opt = f * factor; // double-precision multiplication
if (cr != opt)
printf("For divisor=%a, f=%a, f/divisor=%a but (float)(f*factor)=%a\n",
divisor, f, cr, opt);
}
}
}
O espaço de busca é grande o suficiente para tornar isso interessante (246). O programa está sendo executado no momento. Alguém pode me dizer se vai imprimir alguma coisa, talvez com uma explicação por que ou por que não, antes de terminar?