.NET 4.5.2中对Math.Exp的更改或双重实现 [英] Changes to Math.Exp or double implementation in .net 4.5.2

查看:46
本文介绍了.NET 4.5.2中对Math.Exp的更改或双重实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我运行语句

Math.Exp(113.62826122038274).ToString("R")

在安装了.net 4.5.1的计算机上,然后我得到了答案

on a machine with .net 4.5.1 installed, then I get the answer

2.2290860617259248E+49

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

However, if I run the same command on a machine with .net framework 4.5.2 installed, then I get the answer

2.2290860617259246E+49

(即最后一位数字更改)

(i.e. the final digit changes)

我认识到这在纯数字方面几乎没有什么意义,但是没有人知道.net 4.5.2中所做的任何更改可以解释该更改吗?

I realise that this is broadly insignificant in pure numeric terms, but does anyone know of any changes that have been made in .net 4.5.2 that would explain the change?

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

(I don't prefer one result to the other, I am just interested to understand why it has changed)

如果我输出

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上得到

then on 4.5.1 I get

113.62826122038274
4637696294982039780
2.2290860617259248E+49
5345351685623826106

在4.5.2上我得到:

and on 4.5.2 I get:

113.62826122038274
4637696294982039780
2.2290860617259246E+49
5345351685623826105

因此对于完全相同的输入,我得到的输出是不同的(从位可以看出,因此不涉及往返格式化)

So for the exact same input, I get a different output (as can be seen from the bits so no roundtrip formatting is involved)

更多详细信息:

使用VS2015编译一次

Compiled once using VS2015

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

Both machines that I am running the binaries on are 64bit

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

One has .net 4.5.1 installed, the other 4.5.2

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

Just for clarity: the string conversion is irrelevant... I get the change in results regardless of whether string conversion is involved. I mentioned that purely to demonstrate the change.

推荐答案

令人遗憾的是,浮点数学的奥秘一直困扰着程序员.它与框架版本无关.相关设置是项目">属性">构建"选项卡.

Sigh, the mysteries of floating point math continue to stump programmers forever. It does not have anything to do with the framework version. The relevant setting is Project > Properties > Build tab.

平台目标= x86: 2.2290860617259248E + 49
平台目标= AnyCPU或x64: 2.2290860617259246E + 49

Platform target = x86: 2.2290860617259248E+49
Platform target = AnyCPU or x64: 2.2290860617259246E+49

如果在32位操作系统上运行程序,则始终会得到第一个结果.请注意,往返格式是过度指定的,它包含的数字多于double可以存储的数字.等于15.将它们数掉,得到16.这确保了double的 binary 表示形式,即1和0相同.这两个值之间的差是尾数中的最低有效位.

If you run the program on a 32-bit operating system then you always get the first result. Note that the roundtrip format is overspecified, it contains more digits than a double can store. Which is 15. Count them off, you get 16. This ensures that the binary representation of the double, the 1s and 0s are the same. The difference between the two values is the least significant bit in the mantissa.

LSB不同的原因是因为x86抖动受制于FPU .使用 more 位精度比double可以存储的精度高是非常令人讨厌的属性.80位而不是64位.从理论上讲可以生成更准确的计算结果.可以,但是很少以可重复的方式.对代码的较小更改可能会在计算结果中产生较大的更改.仅在连接了调试器的情况下运行代码才能更改结果,因为这会禁用优化器.

The reason that the LSB is not the same is because the x86 jitter is encumbered with generating code for the FPU. Which has the very undesirable property of using more bits of precision than a double can store. 80 bits instead of 64. Theoretically to generate more accurate calculation results. Which it does, but rarely in a reproducible way. Small changes to the code can produce large changes in the calculation result. Just running the code with a debugger attached can change the result since that disables the optimizer.

英特尔通过SSE2指令集解决了该错误,完全取代了FPU的浮点数学指令.它不使用额外的精度,双精度始终具有64位.由于具有非常理想的属性,即计算结果现在不再依赖于中间存储,因此现在更加一致.但准确性较低.

Intel fixed this mistake with the SSE2 instruction set, completely replacing the floating point math instructions of the FPU. It does not use extra precision, a double always has 64 bits. With the highly desirable property that the calculation result now no longer depends on intermediate storage, it is now much more consistent. But less accurate.

x86抖动使用FPU指令是历史性的意外.2002年发布,支持SSE2的处理器不足.由于该事故改变了程序的可观察行为,因此无法再解决该事故.对于x64抖动来说这不是问题,可以保证64位处理器也支持SSE2.

That the x86 jitter uses FPU instructions is a historical accident. Released in 2002, there were not enough processors around that supported SSE2. That accident cannot be fixed anymore since it changes the observable behavior of a program. It was not a problem for the x64 jitter, a 64-bit processor is guaranteed to also support SSE2.

32位进程使用使用FPU代码的exp()函数.64位进程使用使用SSE代码的exp()函数.结果可能相差一个LSB​​.但仍精确到15个有效数字,它是2.229086061725925E + 49.借助 double ,您可以期待数学之外的一切.

A 32-bit process uses the exp() function that uses FPU code. A 64-bit process uses the exp() function that uses SSE code. The result may be different by one LSB. But still accurate to 15 significant digits, it is 2.229086061725925E+49. All you can ever expect out of math with double.

这篇关于.NET 4.5.2中对Math.Exp的更改或双重实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆