значение 'const float' отличается от 'float' при литье в 'int' в C#

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

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.0999990463256835937, хотя почему это происходит с использованием "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();
}

2 ответов


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

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

и потом у нас есть:

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

теперь, согласно спецификация языка C#:

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

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


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


Я не могу сказать, что это дублирующий вопрос, так как здесь -->Эрик Постпишил комментарий

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

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