在C#中转换为'int'时,'const float'值与'float'不同

joa*_*ose 37 .net c# compiler-bug

你们任何人都可以解释为什么会这样吗?

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();
}
Run Code Online (Sandbox Code Playgroud)

输出:

>const float 35, (int)34
>      float 35, (int)35
Run Code Online (Sandbox Code Playgroud)

我知道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();
}
Run Code Online (Sandbox Code Playgroud)

Dam*_*ver 17

这个的"为什么"基本上归结为这样一个事实,即在处理float数据时,可以使用内部表示,其精度高于float或为double.这在虚拟执行系统(VES)规范(分区I的第12部分)中明确地得到了满足:

浮点数使用内部浮点类型表示.在每个这样的实例中,变量或表达式的名义类型是float32float64,但其值可以在内部用额外的范围和/或精度表示

然后我们有:

当开发人员对其代码进行看似无关的修改时,使用比计算结果更宽float32float64可能导致计算结果差异的内部表示,其结果可能是从内部表示(例如,在寄存器中)溢出值到堆栈上的位置.

现在,根据C#语言规范:

常量表达式的编译时评估使用与非常量表达式的运行时评估相同的规则,除了运行时评估会抛出异常的情况,编译时评估会导致编译时错误发生.

但正如我们在上面所观察到的那样,规则实际上允许有时使用更高的精度,并且当使用这种增强的精度时实际上并不在我们的直接控制之下.


显然,在不同的情况下,结果可能与您观察到的完全相反 - 编译器可能已经降低到较低的精度,而运行时可能会保持更高的精度.