Quando a conversão de Inteiro para Único pode perder precisão


27

Eu estava lendo um artigo da Microsoft sobre como Ampliar conversões e Option Strict On quando cheguei à parte

As conversões a seguir podem perder precisão:

  • Inteiro para Único
  • Longo a Simples ou Duplo
  • Decimal para Simples ou Duplo

No entanto, essas conversões não perdem informações ou magnitude.

.. mas de acordo com outro artigo sobre tipos de dados ,

  • O tipo inteiro pode armazenar de -2.147.483.648 a 2.147.483.647 e

  • Tipo único pode armazenar de

    • 1,401298E-45 a 3,4028235E + 38 para números positivos,
    • e -3,4028235E + 38 a - 1,401298E-45 para números negativos

.. so Single pode armazenar muito mais números que Inteiro. Não conseguia entender em que situação essa conversão de Integer para Single pode perder precisão. Alguém poderia explicar, por favor?

Respostas:


87

Single pode armazenar muito mais números que Inteiro

Não, não pode. Ambos Singlee Integersão 32 bits, o que significa que ambos podem armazenar exatamente a mesma quantidade de números, ou seja, 2 32 = 4294967296 números distintos.

Como o intervalo de Singleé claramente maior que isso, é imediatamente óbvio (por causa do Princípio do Buraco de Buracos ) que ele não pode representar todos os números dentro desse intervalo.

E como o intervalo de Integeré exatamente o mesmo tamanho que a quantidade máxima de números que ambos podem Integere Singlepodem representar, mas Singletambém podem representar números fora desse intervalo, é claro que ele não pode representar todos os números dentro do intervalo de Integer.

Se houver alguns números Integerque não possam ser representados Single, a conversão de Integerpara Single deve ser capaz de perder informações.


3
+1 para este grande explicação de por que isso tem que ser o caso, mesmo que a pergunta era, na verdade, quando ( "em que situação") que acontece ...
Doubleyou

21
@doubleYou: 4261412864 dos 4294967296 Integers (99,2%) não podem ser representados como Single, portanto, "quando" é "praticamente sempre".
Jörg W Mittag

2
Se você quiser ser mais preciso, Singlepode representar apenas 4.278.190.079 números diferentes. Um Singlevalor representa um número se e somente se o expoente armazenado não for 255, o que significa que existem 255 * 2 ^ 24 Singles que representam números. Destes, dois deles representam o mesmo número (ou seja, zero), e os outros representam números diferentes.
Tanner Swett

10
en.wikipedia.org/wiki/Single-precision_floating-point_format explica bem as limitações do IEEE754 binary32. Inteiros em [-16777216,16777216](2 ^ 24 = largura do significando) podem ser exatamente representados. Números maiores são arredondados para o múltiplo mais próximo de 2, 4, 8, ... dependendo do tamanho deles.
Peter Cordes

14
"O que significa que ambos podem armazenar exatamente a mesma quantidade de números" - isso não significa isso. Isso significaria apenas que se os dois tipos tiverem exatamente o mesmo número de maneiras de armazenar cada número. E este não é o caso; por exemplo, Singletem duas maneiras de armazenar zero. Então Single, de fato, pode representar menos números distintos do que Integer.
Konrad Rudolph

28

Os tipos de ponto flutuante (como Single e Double) são representados na memória por um sinal, uma mantissa e um expoente. Pense nisso como notação científica:

Sign*Mantissa*Base^Exponent

Eles - como você pode esperar - usam a base 2. Existem outros ajustes que permitem representar o infinito e o NaN, e o expoente é deslocado (retornará a isso), e uma abreviação para a mantissa (retornará a isso também) . Procure o padrão IEEE 754 que abrange sua representação e operações para obter mais detalhes.

Para nossos propósitos, podemos imaginá-lo como um número binário "mantissa" e um "expoente" que diz onde colocar o separador decimal.


No caso de Single, temos 1 bit para ele assinar, 8 para o expoente e 23 para a mantissa.

Agora, o importante é armazenar a mantissa a partir do dígito mais significativo. Lembre-se de que todos os zeros à esquerda não são relevantes. E, considerando que estamos trabalhando em binário, sabemos que o dígito mais significativo é 1 ※. Bem, como sabemos disso, não precisamos armazená-lo. Graças a essa abreviação, o alcance efetivo da mantissa é de 24 bits.

※: A menos que o número que estamos armazenando seja zero. Para isso, teremos todos os bits definidos como zero. No entanto, se tentarmos interpretar isso sob a descrição que eu dei, você teria 2 ^ 24 (o implícito 1) multiplicado por 1 (2 à potência do expoente 0). Portanto, para corrigi-lo, o expoente zero é um valor especial. Também existem valores especiais para armazenar o infinito e o NaN no expoente.

De acordo com o deslocamento do expoente - além de evitar os valores especiais -, com o deslocamento, é possível colocar o ponto decimal antes do início da mantissa ou após seu término, sem a necessidade de ter um sinal para o expoente.


Isso significa que, para números grandes, o tipo de ponto flutuante colocará o ponto decimal além do final da mantissa.

Lembre-se de que a mantissa é um número de 24 bits. Ele nunca representará um número de 25 bits ... não possui esse bit extra. Portanto, o único não pode distinguir entre 2 ^ 24 e 2 ^ 24 + 1 (esses são os primeiros números de 25 bits e diferem no último bit, que não é representado no único).

Assim, para números inteiros, o intervalo do único é -2 ^ 24 a 2 ^ 24. E tentar adicionar 1 a 2 ^ 24 resultará em 2 ^ 24 (porque, no que diz respeito ao tipo, 2 ^ 24 e 2 ^ 24 + 1 são o mesmo valor). Experimente online . É por isso que há uma perda de informações ao converter de número inteiro para único. E é também por isso que um loop que usa um único ou um duplo pode realmente ser um loop infinito sem você perceber.


Esta não é uma explicação perfeita do 1bit implícito inicial no significando. Está implícito que o campo de expoente tendencioso é diferente de zero . Os subnormais (também conhecidos como denormais) incluem+-0.0 um 0pouco do seu significado. Eu acho que você pode simplificar para considerar apenas 0.0um caso totalmente especial, mas 0.0na verdade segue as mesmas regras de codificação de outros subnormais.
Peter Cordes

25

Aqui está um exemplo real de quando a conversão de Integerpara Singlepode perder precisão:

O Singletipo pode armazenar todos os números inteiros de -16777216 a 16777216 (inclusive), mas não pode armazenar todos os números inteiros fora desse intervalo. Por exemplo, ele não pode armazenar o número 16777217. Por esse motivo, não pode armazenar nenhum número ímpar maior que 16777216.

Podemos usar o Windows PowerShell para ver o que acontece se convertermos um Integerem um Singlee vice-versa:

PS C:\Users\tanne> [int][float]16777213
16777213
PS C:\Users\tanne> [int][float]16777214
16777214
PS C:\Users\tanne> [int][float]16777215
16777215
PS C:\Users\tanne> [int][float]16777216
16777216
PS C:\Users\tanne> [int][float]16777217
16777216
PS C:\Users\tanne> [int][float]16777218
16777218
PS C:\Users\tanne> [int][float]16777219
16777220

Observe que 16777217 foi arredondado para 16777216 e 16777219 foi arredondado para 16777220.


4
E com magnitude crescente, a distância entre os floats representáveis ​​mais próximos continua crescendo como potências de. pt.wikipedia.org/wiki/…
Peter Cordes em

12

Os tipos de ponto flutuante são semelhantes à "notação científica" em física. O número é dividido em um bit de sinal, um expoente (multiplicador) e uma mantissa (dígitos significativos). Assim, à medida que a magnitude do valor aumenta, o tamanho da etapa também aumenta.

O ponto flutuante de precisão única possui 23 bits de mantissa, mas existe um "1 implícito"; portanto, o mantissa é efetivamente de 24 bits. Portanto, todos os números inteiros com magnitude de até 2 24 podem ser representados exatamente em um ponto flutuante de precisão única.

Acima disso, sucessivamente menos números podem ser representados.

  • De 2 24 a 2 25 apenas números pares podem ser representados.
  • De 2 25 a 2 26 apenas múltiplos de 4 podem ser representados.
  • De 2 26 a 2 27, apenas múltiplos de 8 podem ser representados.
  • De 2 27 a 2 28, apenas múltiplos de 16 podem ser representados
  • De 2 28 a 2 29 apenas múltiplos de 32 podem ser representados
  • De 2 29 a 2 30, apenas múltiplos de 64 podem ser representados
  • De 2 30 a 2 31, apenas múltiplos de 128 podem ser representados

Portanto, dos 2 32 possíveis valores inteiros assinados de 32 bits, apenas 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 podem ser representados em um ponto flutuante de precisão única. Isso representa 3,515625% do total.


8

Os flutuadores de precisão única têm 24 bits de precisão. Tudo o que for arredondado para o número de 24 bits mais próximo. Pode ser mais fácil entender em notação científica decimal, mas lembre-se de que os flutuadores reais usam binário.

Digamos que você tenha 5 dígitos decimais de memória. Você pode optar por usá-los como um int não assinado regular, permitindo que você tenha qualquer número entre 0 e 99999. Se quiser representar números maiores, use a notação científica e aloque apenas dois dígitos para o expoente, portanto agora você pode representar algo entre 0 e 9,99 x 10 99 .

No entanto, o maior número que você pode representar exatamente agora é apenas 999. Se você tentou representar 12345, pode obter 1,23 x 10 4 ou 1,24 x 10 4 , mas não pode representar nenhum dos números intermediários, porque não tem dígitos suficientes disponíveis.


3
Usar dígitos decimais é uma boa idéia que facilita a compreensão, mas o último parágrafo é um pouco enganador: na verdade, você pode representar números maiores que 999, e seu exemplo mostra: 12300 seria 1,23 x 10 <sup> 4 <sup >. O que você quer dizer é que a partir desse número, existem lacunas. Você se importaria de reformular um pouco?
Fabio diz Reinstate Monica em
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.