37

你们中的任何人都可以解释为什么会发生这种情况吗?

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

2 回答 2

17

这个“为什么”基本上可以归结为这样一个事实,即在处理float数据时,经常使用比为floator指定的精度更高的内部表示double这在 Virtual Execution System (VES) Spec( Partition I的第 12 节)中得到了明确的照顾:

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

然后我们有:

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

现在,根据C# 语言规范

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

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


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

于 2014-06-03T13:52:27.523 回答
1

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

解释了有关 int 和 const int 的非常相似的内容。

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

于 2014-06-03T14:06:21.243 回答