C# 32位过程中类型转换后的错误值

C# 32位过程中类型转换后的错误值,c#,casting,floating-point,32bit-64bit,C#,Casting,Floating Point,32bit 64bit,请参阅C#中的以下代码 为什么我们在32位进程中得到99 我使用的是VS2013。当您直接操作时,允许以更高的精度执行操作,并允许在多个操作中继续使用更高的精度 根据C#5规范第4.1.6节: 浮点运算的执行精度可能高于运算的结果类型。例如,某些硬件体系结构支持“扩展”或“长双精度”浮点类型,其范围和精度比双精度类型更大,并使用此高精度类型隐式执行所有浮点操作。只有在性能成本过高的情况下,这样的硬件体系结构才能以较低的精度执行浮点运算,并且C#允许对所有浮点运算使用更高精度的类型,而不是要求实现

请参阅C#中的以下代码

为什么我们在32位进程中得到99


我使用的是VS2013。

当您直接操作时,允许以更高的精度执行操作,并允许在多个操作中继续使用更高的精度

根据C#5规范第4.1.6节:

浮点运算的执行精度可能高于运算的结果类型。例如,某些硬件体系结构支持“扩展”或“长双精度”浮点类型,其范围和精度比双精度类型更大,并使用此高精度类型隐式执行所有浮点操作。只有在性能成本过高的情况下,这样的硬件体系结构才能以较低的精度执行浮点运算,并且C#允许对所有浮点运算使用更高精度的类型,而不是要求实现同时丧失性能和精度。除了提供更精确的结果,这很少有任何可测量的效果。然而,在形式为x×y/z的表达式中,其中乘法产生的结果在双范围之外,但是随后的除法将临时结果带回到双范围中,以更高范围格式计算表达式的事实可能导致产生有限结果而不是无穷大

我希望在某些优化场景中,如果JIT决定它从来都不需要将该值作为
浮点值
,那么对于额外的局部变量,答案甚至可能是“错误的”。(我见过这样的情况,仅仅添加日志记录就改变了这里的行为…)

在这种情况下,我相信除法是使用64位算术有效地执行的,然后从
double
直接转换为
int
,而不是先通过
float
执行

下面是一些代码,用
DoubleConverter
类来演示,该类允许您查找浮点二进制数的精确十进制表示:

using System;

class Test
{
    static void Main()
    {
        float a = 10f;
        float b = 0.1f;
        float c = a / b;
        double d = (double) a / (double) b;
        float e = (float) d;
        Console.WriteLine(DoubleConverter.ToExactString(c));
        Console.WriteLine(DoubleConverter.ToExactString(d));
        Console.WriteLine(DoubleConverter.ToExactString(e));
        Console.WriteLine((int) c);
        Console.WriteLine((int) d);
        Console.WriteLine((int) e);
    }
}
输出:

100
99.999998509883909036943805404007434844970703125
100
100
99
100
请注意,该操作可能不仅仅以64位执行,还可能以更高的精度执行,例如80位

这只是浮点二进制算术的乐趣之一,也是一个例子,说明了为什么你在做什么时需要非常小心


请注意,0.1f正好是0.100000001490119384765625,因此大于0.1。考虑到它大于0.1,我预计
10/b
将略小于100-如果“略小于”是可表示的,那么截断结果自然会导致99。

从内存中,标准说“这是特定于实现的”-因此精度可能因平台而异。再一次-一个难以置信的答案如此迅速+1@SimonWhitehead:是的-添加了一个规范参考以进行更多解释。这不是“浮点二进制算术的乐趣”。这是1)未指定的编程语言定义和2)依附于12年前已经过时的ABI和指令集的实现的乐趣。定义不必不明确(即C99、Java),而且自从2001年引入SSE2以来,实现现在就可以很容易地开始使用它了。@Jon:感谢您立即给出详细的答复。:)
100
99.999998509883909036943805404007434844970703125
100
100
99
100