Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET4.5.2中对Math.Exp或double实现的更改_C#_Precision_.net 4.5.2 - Fatal编程技术网

C# 在.NET4.5.2中对Math.Exp或double实现的更改

C# 在.NET4.5.2中对Math.Exp或double实现的更改,c#,precision,.net-4.5.2,C#,Precision,.net 4.5.2,如果我运行语句 Math.Exp(113.62826122038274).ToString("R") 在安装了.NET4.5.1的机器上,我得到了答案 2.2290860617259248E+49 2.2290860617259246E+49 但是,如果我在安装了.net framework 4.5.2的计算机上运行相同的命令,那么我会得到答案 2.2290860617259248E+49 2.2290860617259246E+49 (即最后的数字变化) 我意识到,从纯数字的角度来看

如果我运行语句

Math.Exp(113.62826122038274).ToString("R")
在安装了.NET4.5.1的机器上,我得到了答案

2.2290860617259248E+49
2.2290860617259246E+49
但是,如果我在安装了.net framework 4.5.2的计算机上运行相同的命令,那么我会得到答案

2.2290860617259248E+49
2.2290860617259246E+49
(即最后的数字变化)

我意识到,从纯数字的角度来看,这基本上是无关紧要的,但有人知道.net 4.5.2中所做的任何更改可以解释这一更改吗

(我不喜欢一个结果而不喜欢另一个,我只是想了解它为什么发生了变化)

如果我输出

The input in roundtrip format
The input converted to a long via BitConverter.DoubleToInt64Bits
Math.Exp in roundtrip format
Math.Exp converted to a long via BitConverter.DoubleToInt64Bits
然后在4.5.1我得到

113.62826122038274
4637696294982039780
2.2290860617259248E+49
5345351685623826106
在4.5.2中,我得到:

113.62826122038274
4637696294982039780
2.2290860617259246E+49
5345351685623826105
因此,对于完全相同的输入,我得到不同的输出(从位可以看出,因此不涉及往返格式)

更多详情:

使用VS2015编译一次

我运行二进制文件的两台机器都是64位的

一个安装了.net 4.5.1,另一个安装了.net 4.5.2


为了清楚起见:字符串转换是不相关的。。。无论是否涉及字符串转换,我都会得到结果的变化。我提到这一点纯粹是为了证明这种变化

.NET使用CRT中的数学库函数进行这些计算。.NET使用的CRT通常随每个版本更新,因此您可以预期.NET版本之间的结果会发生变化,但是,它们始终在承诺的+/1ulp范围内。

我遇到了相同的问题,但我只有在安装.NET 4.6后才得到它

.Net 4.6安装升级了c:\windows\system32\msvcr120\u clr0400.dll和c:\windows\syswow64\msvc120\u clr0400.dll

在安装之前,这些DLL具有文件属性->详细信息:“文件版本12.0.51689.34249”和“产品名称Microsoft Visual Studio 12 CTP”

在安装.net 4.6之后,它们有“文件版本12.0.52512.0”和“产品名称Microsoft Visual Studio 2013”

我调整了测试以包含您的示例,通过在这个DLL的版本之间切换,我看到了与您相同的前后数字


(我们的测试套件在.net版本4、4.5、4.5.1或4.5.2上运行时没有显示任何更改的结果,直到这些DLL被更新。)

唉,浮点数学的奥秘永远困扰着程序员。它与框架版本没有任何关系。相关设置为“项目>属性>生成”选项卡

平台目标=x86:
2.2290860617259248E+49

平台目标=任何CPU或x64:
2.2290860617259246E+49

如果在32位操作系统上运行该程序,则始终会得到第一个结果。请注意,往返格式指定过多,它包含的数字比双精度存储的数字多。这是15。数一数,你得到16分。这确保了double、1s和0s的二进制表示形式相同。两个值之间的差值是尾数中的最低有效位

LSB不一样的原因是x86抖动被为生成代码所困扰。它有一个非常不受欢迎的特性,即使用的精度比特数超过了双精度存储器所能存储的比特数。80位而不是64位。从理论上讲,可以生成更精确的计算结果。确实如此,但是。对代码的微小更改可能会对计算结果产生较大的更改。只要在附加了调试器的情况下运行代码就可以更改结果,因为这样会禁用优化器

英特尔用SSE2指令集修复了这个错误,完全取代了FPU的浮点数学指令。它不需要额外的精度,一个double总是有64位。由于计算结果现在不再依赖于中间存储这一非常理想的特性,它现在更加一致。但不太准确

x86抖动使用FPU指令是一个历史事故。在2002年发布的版本中,没有足够的处理器支持SSE2。该事故无法再修复,因为它改变了程序的可观察行为。x64抖动不是问题,64位处理器保证也支持SSE2


32位进程使用使用FPU代码的exp()函数。64位进程使用使用SSE代码的exp()函数。一个LSB的结果可能不同。但仍然精确到15位有效数字,它是2.229086061725925E+49。使用double,您可以从数学中得到所有期望。

为了说明针对不同.NET版本的项目如何影响字符串的双重转换,我构建了4个针对不同版本的项目,所有这些项目都运行在使用.NET 4.6的同一台开发机器上

这是密码

double foo = Convert.ToDouble("33.94140881672595");
这是输出

33.941408816725954(.NET 4)

33.941408816725946(.净额4.5)

33.941408816725946(.NET 4.5.2)

33.941408816725946(.NET 4.6)


因此,在安装了.NET 4之后,转换方法肯定发生了变化。@AndreasMüller-不,只有4.5.2,尽管4.6与4.5.2的答案相同-这一变化似乎是由4.5.2而不是4引入的。6@WaiHaLee请参阅更新的问题浮点操作由CPU执行,而不是由框架执行。CPU之间有区别吗?这种差异也可能是由一个使用FPU的框架和另一个使用SSE的框架造成的。4.5.2没有做出这样的更改,但4.6引入了SIMD操作。4.6是4.5的二进制替换,所以这可能是导致我的机器与
4.5.2
不同的原因。我得到了你的第一个结果,最后的数字以8结尾,而不是6,
2.2290806172598E+49
@flq-C Runtime。它的编译器附带了微软的C标准库。这篇文章有很多好的信息:我不相信这解释了“Math.Exp在安装.NET 4.6.1并应用KB3098785后返回不同的结果”,我告诉过你该怎么做。请自己尝试一下,更改平台目标并观察x86生成0.71612515940795685,x64生成0.716125