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

时间:2014-06-03 13:19:52

标签: c# .net 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();
}

输出:

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

我知道0.1的二进制表示实际上是0.09999990463256835937,但为什么会发生这种情况使用' const 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 个答案:

答案 0 :(得分:17)

"为什么"其中基本上归结为这样一个事实:当使用float数据时,可能会使用内部表示,其精度高于为floatdouble指定的精度。这在虚拟执行系统(VES)规范中明确提供(Partition I的第12节):

  

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

然后我们有:

  

使用宽于float32float64的内部表示可能会导致差异   当开发人员对他们的代码进行看似无关的修改时的计算结果   这可能是一个值从内部表示(例如,在寄存器中)溢出到一个位置   叠加。

现在,根据C# language specification

  

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

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


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

答案 1 :(得分:1)

我不能说这是一个重复的问题,因为在这里 - > Eric Postpischil comment

解释了关于int和const int的非常相似的东西。

主要思想是在生成代码之前由编译器计算的两个常量的划分而不是在运行时,但在这种特定情况下,只要编译器执行此操作,它就会执行 double 格式。因此xScaleSizeC基本上等于34.9999 ...因此当它在运行时转换为int时它变为34。