Подтвердить что ты не робот

Значение "const float" отличается от "float" при кастинге на "int" в С#

Может кто-нибудь из вас объяснить, почему это происходит?

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

Вывод:

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

Я знаю, что двоичное представление 0,1 на самом деле является 0.09999990463256835937, хотя почему это происходит с использованием 'const float', а не с 'float'? Это считается ошибкой компилятора?

Для записи код компилируется в:

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

Ответ 1

"Почему" этого в основном сводится к тому, что часто при работе с данными float может использоваться внутреннее представление, которое имеет большую точность, чем указано для float или double. Это явно учитывается в спецификации виртуальной исполнительной системы (VES) (раздел 12 раздела раздел I):

числа с плавающей запятой представлены с использованием внутренней с плавающей запятой тип. В каждом таком случае номинальный тип переменной или выражения равен либо float32, либо float64, но его значение может быть представлено внутри с дополнительным диапазоном и/или точностью

И потом мы имеем:

Использование внутреннего представления, которое больше, чем float32 или float64, может привести к различиям в вычислительные результаты, когда разработчик делает, по-видимому, несвязанные модификации своего кода, результат который может быть таким, что значение выводится из внутреннего представления (например, в регистре) в местоположение на стек.

Теперь, в соответствии с спецификацией языка С#:

Оценка констант во время компиляции использует те же правила, что и оценка времени выполнения неконстантных выражений во время выполнения, за исключением того, что когда оценка времени выполнения выдала исключение, оценка времени компиляции вызывает ошибку времени компиляции происходят.

Но, как мы видим выше, правила на самом деле позволяют использовать более точную точность, и когда эта расширенная точность используется, на самом деле не находится под нашим прямым контролем.


И, очевидно, в разных обстоятельствах результаты могли быть точно противоположны тому, что вы наблюдали, - компилятор, возможно, снизился до более низкой точности, а время выполнения могло поддерживать более высокую точность.

Ответ 2

Я не могу сказать, что это дублирующий вопрос, так как здесь → Eric Postpischil comment

объяснил что-то очень похожее относительно int и const int.

Основная идея заключается в том, что разделение двух констант, вычисленное компилятором перед генерированием кода, а не во время выполнения, НО в этом конкретном случае всякий раз, когда компилятор делает это, он выполняет вычисления в double. Таким образом, xScaleSizeC в основном равен 34.9999... поэтому, когда он получает приведение во время выполнения к int, он становится 34.