Pergunta

Algum de vocês pode explicar por que isso acontece?

static void Main()
{
    const float xScaleStart = 0.5f;
    const float xScaleStop = 4.0f;
    const float xScaleInterval = 0.1f;
    const float xScaleAmplitude = xScaleStop - xScaleStart;

    const float xScaleSizeC = xScaleAmplitude / xScaleInterval;

    float xScaleSize = xScaleAmplitude / xScaleInterval;

    Console.WriteLine(">const float {0}, (int){1}", xScaleSizeC, (int)xScaleSizeC);

    Console.WriteLine(">      float {0}, (int){1}", xScaleSize, (int)xScaleSize);

    Console.ReadLine();
}

Saída:

>const float 35, (int)34
>      float 35, (int)35

Eu sei que a representação binária de 0,1 é na verdade 0,09999990463256835937, mas por que isso acontece usando 'const float' e não com 'float'?Isso é considerado um bug do compilador?

Para registro, o código é compilado em:

private static void Main(string[] args)
{
    float xScaleSize = 35f;
    Console.WriteLine(">const float {0}, (int){1}", 35f, 34);
    Console.WriteLine(">      float {0}, (int){1}", xScaleSize, (int)xScaleSize);
    Console.ReadLine();
}
Foi útil?

Solução

O “porquê” disso se resumirá basicamente ao fato de que frequentemente, ao trabalhar com float dados, uma representação interna pode ser usada com mais precisão do que a especificada para float ou double.Isso é explicitamente contemplado na Especificação do Sistema de Execução Virtual (VES) (seção 12 do Partição I):

Os números de ponto flutuante são representados usando um tipo de ponto flutuante interno.Em cada um desses casos, o tipo nominal da variável ou expressão é float32 ou float64, mas seu valor pode ser representado internamente com intervalo adicional e/ou precisão

E mais tarde temos:

O uso de uma representação interna que seja mais ampla do que float32 ou float64 pode causar diferenças nos resultados computacionais quando um desenvolvedor faz modificações aparentemente não relacionadas ao seu código, cujo resultado pode ser que um valor é derramado da representação interna (por exemplo, em um registro) para um local na pilha.

Agora, de acordo com o Especificação da linguagem C#:

A avaliação em tempo de compilação de expressões constantes usa as mesmas regras que a avaliação em tempo de execução de expressões não constantes, exceto que onde a avaliação em tempo de execução teria gerado uma exceção, a avaliação em tempo de compilação causaria a ocorrência de um erro em tempo de compilação.

Mas, como observamos acima, às vezes as regras permitem que mais precisão seja usada, e quando essa precisão aprimorada é usada, na verdade não está sob nosso controle direto.


E obviamente, em circunstâncias diferentes, os resultados poderiam ter sido exatamente o oposto do que você observou - o compilador pode ter caído para uma precisão mais baixa e o tempo de execução poderia ter mantido uma precisão mais alta.

Outras dicas

Não posso dizer que esta seja uma pergunta duplicada, pois aqui -> Comentário de Eric Postpischil

explicou algo muito semelhante em relação a int e const int.

A ideia principal é que a divisão de duas constantes calculadas pelo compilador antes de gerar o código e não em tempo de execução, MAS neste caso específico sempre que o compilador fizer isso ele realiza os cálculos em dobro formatar.Assim, o xScaleSizeC é basicamente igual a 34,9999...então, quando for convertido em tempo de execução para int, ele se tornará 34.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top