37 votes

'const float' valeur différente de "flotter", lors de la conversion de int en C#

Qui de vous expliquer pourquoi cela se produit?

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();
}

Sortie:

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

Je sais que la représentation binaire de 0,1 est en fait 0.09999990463256835937, mais pourquoi cela se produit à l'aide de 'const float" et pas avec "flotter"? Est-ce considéré comme un bogue du compilateur?

Pour l'enregistrement, le code se compile en:

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();
}

17voto

Damien_The_Unbeliever Points 102139

Le "Pourquoi" de ce va se résument au fait que, souvent, lorsque vous travaillez avec des float données, une représentation interne peut être utilisé qui est plus précis que ce qui est spécifié pour float ou double. C'est explicitement pris en compte dans le Virtuel du Système d'Exécution (VES) Spec (article 12 de la Partition j'ai):

les nombres à virgule flottante sont représentés à l'aide d'une virgule flottante interne type. Dans chacun de ces cas, la valeur nominale type de la variable ou l'expression est soit float32 ou float64, mais son la valeur peut être représentée en interne avec d'autres offres et/ou de précision

Et puis plus tard, nous avons:

L'utilisation d'une représentation interne qui est plus large que float32 ou float64 peut entraîner des différences dans résultats de calculs lorsqu'un développeur fait apparemment sans rapport avec les modifications de code, le résultat de qui peut être qu'une valeur est répandu à partir de la représentation interne (par exemple, dans un registre) à un emplacement sur le la pile.

Maintenant, en fonction de la spécification du langage C# :

Le moment de la compilation de l'évaluation des expressions constantes utilise les mêmes règles que le temps d'exécution de l'évaluation de la non-expressions constantes, sauf que au moment de l'exécution de l'évaluation aurait jeté une exception, au moment de la compilation d'évaluation provoque une erreur de compilation à se produire.

Mais comme nous l'observer ci-dessus, les règles permettent plus de précision pour être utilisé de temps en temps, et quand cette amélioration de la précision est utilisé n'est pas sous notre contrôle direct.


Et, évidemment, dans des circonstances différentes, le résultat aurait été exactement le contraire de ce que vous avez observé - le compilateur a peut-être abandonné à la baisse de la précision et de l'exécution pourrait avoir maintenu une plus grande précision à la place.

1voto

Skalik Points 36

Je ne peux pas dire que c'est une double question depuis ici --> Eric Postpischil commentaire

d'expliquer quelque chose de très similaire concernant int et const int.

L'idée principale est que la division de deux constantes calculées par le compilateur avant de générer le code et non pas au moment de l'exécution, MAIS dans ce cas précis, à chaque fois que le compilateur n'cela, il effectue les calculs en double format. Ainsi, le xScaleSizeC est essentiellement égale 34.9999... donc quand il se cast en run-time type int, il devient 34.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X