Jep*_*sen 7 c# floating-point clr 64-bit single-precision
当您阅读MSDN时System.Single
:
Single
符合IEC 60559:1989(IEEE 754)二进制浮点运算标准.
和C#语言规范:
这些
float
和double
类型使用32位单精度和64位双精度IEEE 754格式表示[...]
然后:
根据IEEE 754算法的规则计算产品.
您很容易得到float
类型及其乘法符合IEEE 754 的印象.
IEEE 754的一部分是多重定义.我的意思是,当你有两个float
实例时,存在一个且只有一个float
是他们的"正确"产品.不允许产品依赖于计算系统的某些"状态"或"设置".
现在,考虑以下简单程序:
using System;
static class Program
{
static void Main()
{
Console.WriteLine("Environment");
Console.WriteLine(Environment.Is64BitOperatingSystem);
Console.WriteLine(Environment.Is64BitProcess);
bool isDebug = false;
#if DEBUG
isDebug = true;
#endif
Console.WriteLine(isDebug);
Console.WriteLine();
float a, b, product, whole;
Console.WriteLine("case .58");
a = 0.58f;
b = 100f;
product = a * b;
whole = 58f;
Console.WriteLine(whole == product);
Console.WriteLine((a * b) == product);
Console.WriteLine((float)(a * b) == product);
Console.WriteLine((int)(a * b));
}
}
Run Code Online (Sandbox Code Playgroud)
通过写一些关于环境的信息并编译配置,该程序只考虑两个float
(即a
和b
)及其产品.最后四个写行是有趣的.这是使用Debug x86(左),Release x86(中)和x64(右)编译后在64位机器上运行它的输出:
我们得出结论,简单float
操作的结果取决于构建配置.
后面的第一行"case .58"
是对两个float
s 相等的简单检查.我们希望它独立于构建模式,但事实并非如此.接下来的两行我们希望是相同的,因为它不会改变任何东西来转换float
为a float
.但他们不是.我们也希望他们阅读,"True? True"
因为我们正在将产品a*b
与自身进行比较.我们希望输出的最后一行与构建配置无关,但事实并非如此.
为了弄清楚正确的产品是什么,我们手动计算.0.58
(a
)的二进制表示是:
0 . 1(001 0100 0111 1010 1110 0)(001 0100 0111 1010 1110 0)...
Run Code Online (Sandbox Code Playgroud)
括号中的块是永远重复的周期.此数字的单精度表示需要四舍五入为:
0 . 1(001 0100 0111 1010 1110 0)(001 (*)
Run Code Online (Sandbox Code Playgroud)
我们已经舍入(在这种情况下向下舍入)到最近的可表示Single
.现在,数字"一百"(b
)是:
110 0100 . (**)
Run Code Online (Sandbox Code Playgroud)
在二进制.计算数字的完整产品(*)
并(**)
给出:
11 1001 . 1111 1111 1111 1111 1110 0100
Run Code Online (Sandbox Code Playgroud)
舍入(在这种情况下舍入)到单精度给出
11 1010 . 0000 0000 0000 0000 00
Run Code Online (Sandbox Code Playgroud)
在那里我们四舍五入,因为下一位是1
,而不是0
(舍入到最近).因此我们得出结论,结果是58f
根据IEEE.根据IEEE,这不是先验地给出的,例如0.59f * 100f
小于59f
和0.60f * 100f
大于60f
.
所以看起来代码的x64版本是正确的(上图中最右边的输出窗口).
注意:如果此问题的任何读者都有一个旧的32位CPU,那么听听上述程序的输出在他们的体系结构上会很有趣.
现在问题是:
float
额外的精度执行乘法,然后"忘记"再次摆脱该精度?float
表达式转换为类型float
更改任何内容?(a*b)
为一个临时局部变量,改变行为,当它们应该在数学上(根据IEEE)等效时,这不是一个问题吗?如果运行时选择保持float
"人为"额外(64位)精度,程序员如何才能提前知道?(这是在.NET Framework的4.0版本中完成的.)
我没有检查过你的算术,但我以前看到过类似的结果.除了调试模式有所不同之外,分配局部变量和实例变量也会产生影响.根据C#4规范的4.1.6节,这是合法的:
可以以比操作的结果类型更高的精度执行浮点运算.例如,某些硬件体系结构支持"扩展"或"长双"浮点类型,其范围和精度高于
double
类型,并使用此更高精度类型隐式执行所有浮点运算.只有在性能成本过高的情况下,才能使这种硬件架构以较低的精度执行浮点运算.C#允许更高精度的类型用于所有浮点运算,而不是要求实现放弃性能和精度.除了提供更精确的结果外,这几乎没有任何可衡量的影响.[...]
我不能肯定地说这是不是在这里发生了什么,但我不会感到惊讶.
归档时间: |
|
查看次数: |
424 次 |
最近记录: |