precisão 'float' vs. 'double'

155

O código

float x  = 3.141592653589793238;
double z = 3.141592653589793238;
printf("x=%f\n", x);
printf("z=%f\n", z);
printf("x=%20.18f\n", x);
printf("z=%20.18f\n", z);

lhe dará a saída

x=3.141593
z=3.141593
x=3.141592741012573242
z=3.141592653589793116

onde na terceira linha de saída 741012573242é lixo e na quarta linha 116é lixo. Os duplos sempre têm 16 números significativos, enquanto os carros alegóricos sempre têm 7 números significativos? Por que as duplas não têm 14 números significativos?

foo
fonte

Respostas:

146

Os números de ponto flutuante em C usam a codificação IEEE 754 .

Esse tipo de codificação usa um sinal, um significando e um expoente.

Devido a essa codificação, muitos números terão pequenas alterações para permitir que sejam armazenados.

Além disso, o número de dígitos significativos pode mudar um pouco, pois é uma representação binária, não decimal.

A precisão única (flutuante) fornece 23 bits de significando, 8 bits de expoente e 1 bit de sinal.

A precisão dupla (dupla) fornece 52 bits de significando, 11 bits de expoente e 1 bit de sinal.

Alan Geleynse
fonte
4
C99, anteriormente era do compilador.
Alan Geleynse 23/02
21
-1 Esta afirmação é descaradamente falsa: "Devido a essa codificação, você nunca pode garantir que não terá uma alteração no seu valor".
R .. GitHub Pare de ajudar o gelo 23/02
16
@ Alan: C99 não requer ponto flutuante IEEE; apenas recomenda.
R .. GitHub Pare de ajudar o gelo 23/02
4
@ Alan: R .. está correto; O anexo F (que especifica as ligações IEEE-754) é normativo, mas somente em vigor se uma implementação definir __STDC_IEC_559__. Uma implementação que não define essa macro é livre para não estar em conformidade com a IEEE-754.
Stephen Canon
12
@Alan: Sob IEEE 754, é facilmente garantido que não há nenhuma mudança nos valores 0.5, 0.046875ou 0.376739501953125contra suas representações decimais. (Todos esses são racionais diádicos com ajuste de numerador na mantissa e logaritmo de base 2 do ajuste de denominador no expoente.)
R .. GitHub STOP HELPING ICE
42

Os duplos sempre têm 16 números significativos, enquanto os carros alegóricos sempre têm 7 números significativos?

Não. As duplas sempre têm 53 bits significativos e os flutuadores sempre têm 24 bits significativos (exceto para valores anormais, infinitos e NaN, mas esses são assuntos para uma pergunta diferente). Esses são formatos binários, e você só pode falar claramente sobre a precisão de suas representações em termos de dígitos binários (bits).

Isso é análogo à questão de quantos dígitos podem ser armazenados em um número inteiro binário: um número inteiro de 32 bits não assinado pode armazenar números inteiros com até 32 bits, o que não é mapeado com precisão para qualquer número de dígitos decimais: todos os números inteiros de até É possível armazenar 9 dígitos decimais, mas muitos números de 10 dígitos também podem ser armazenados.

Por que as duplas não têm 14 números significativos?

A codificação de um duplo usa 64 bits (1 bit para o sinal, 11 bits para o expoente, 52 bits significativos explícitos e um bit implícito), que é o dobro do número de bits usados ​​para representar um float (32 bits).

Stephen Canon
fonte
15

float: 23 bits de significando, 8 bits de expoente e 1 bit de sinal.

double: 52 bits de significando, 11 bits de expoente e 1 bit de sinal.

abe312
fonte
11

Geralmente, ele é baseado em números significativos do expoente e do significando na base 2, e não na 10. Com base no que posso dizer no padrão C99, no entanto, não há precisão especificada para flutuadores e duplos (além do fato de que 1 e 1 + 1E-5/ 1 + 1E-7são distinguíveis [ floatedouble repsectivamente]). No entanto, o número de números significativos é deixado para o implementador (bem como qual base eles usam internamente, portanto, em outras palavras, uma implementação pode decidir fazê-lo com base em 18 dígitos de precisão na base 3). [1]

Se você precisar conhecer esses valores, as constantes FLT_RADIXe FLT_MANT_DIG(e DBL_MANT_DIG/ LDBL_MANT_DIG) são definidas em float.h.

O motivo pelo qual é chamado a doubleé porque o número de bytes usados ​​para armazená-lo é o dobro do número de um float (mas isso inclui o expoente e o significando). O padrão IEEE 754 (usado pela maioria dos compiladores) aloca relativamente mais bits para o significando do que para o expoente (23 a 9 para floatvs. 52 a 12 para double), e é por isso que a precisão é mais do que duplicada.

1: Seção 5.2.4.2.2 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf )

user470379
fonte
Erro de digitação? O C89 requer um epsilon de no máximo 1E-9para double, não 1E-7.
Rufflewind
10

Um flutuador possui 23 bits de precisão e um duplo possui 52.

Chris Nash
fonte
Detalhe: o binary64 possui uma significância de 53 bits (52 armazenada explicitamente) e o binary32 possui 24 bits (23 explicitamente armazenados).
chux - Restabelece Monica
4

Não é exatamente precisão dupla por causa de como o IEEE 754 funciona, e porque o binário não é realmente traduzido corretamente para decimal. Dê uma olhada no padrão, se você estiver interessado.

user541686
fonte
4

float significa número de ponto flutuante. Em C, o tipo de dado float é usado nos casos em que a precisão do número total de dígitos é 7. Por exemplo: - o número decimal. 12.3546987 não pode ser armazenado no float porque possui um total de 9 dígitos. A saída será mostrada como 12.354699, ou seja, os primeiros 7 dígitos serão mostrados conforme digitados na entrada e o oitavo dígito será arredondado. O tipo de flutuador pode representar valores variando de aproximadamente 1,5 x 10 ^ (- 45) a 3,4 x 10 ^ (38). Em termos de alocação de memória, float é um tipo de dados de ponto flutuante de precisão única e 32 bits.

Ao contrário do float, o double tem uma precisão de 15 a 16 dígitos.O intervalo de double é de 5,0 × 10 ^ (- 345) a 1,7 × 10 ^ (308). Em termos de alocação de bytes, double é um dado de ponto flutuante de 64 bits tipo.

O problema surge no seu uso. Float ou double não afeta printf, mas no caso de scanf, o tipo de dados apropriado deve ser usado, dependendo do número total. de dígitos no número flutuante. isso deve ser lido da entrada.

Portanto, o dobro é preferido sobre o float para maior precisão dos dados.

Espero que isto ajude.

Vineeth Krishna K
fonte