首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >浮点数学在C#中是一致的吗?可能是吗?

浮点数学在C#中是一致的吗?可能是吗?
EN

Stack Overflow用户
提问于 2011-07-13 17:29:55
回答 10查看 17.1K关注 0票数 159

不,这不是另一个“为什么是(1/3.0)*3 != 1”的问题。

最近我读了很多关于浮点数的文章,特别是相同的计算如何在不同的架构或优化设置上给出不同的结果()。

对于存储重播的电子游戏,或者是点对点联网 (相对于服务器-客户端)来说,这是一个问题,它依赖于所有客户端每次运行程序时都产生完全相同的结果--一个浮点计算中的微小差异可能会导致不同机器(甚至在同一台机器上!)上的游戏状态大不相同。

即使在“遵循”IEEE-754的处理器中也会发生这种情况,这主要是因为一些处理器(即x86)使用双扩展精度。也就是说,他们使用80位寄存器来做所有的计算,然后截断到64位或32位,导致与使用64位或32位的机器不同的四舍五入结果。

我在网上看到了几种解决这个问题的方法,但都是针对C++的,而不是C#:

  • 禁用双扩展精度模式(使所有double计算使用IEEE-754 64位)使用_controlfp_s (_controlfp_s)、_FPU_SETCW (Linux?)或fpsetprec (BSD)。
  • 始终使用相同的优化设置运行相同的编译器,并要求所有用户具有相同的CPU架构(没有跨平台播放)。因为我的“编译器”实际上是JIT,每次运行时都可能对其进行不同的优化,所以我认为这是不可能的。
  • 使用定点算法,完全避免floatdouble .decimal将为此目的工作,但速度要慢得多,而且没有一个System.Math库函数支持它。

那么,,这在C#中甚至是一个问题吗?,如果我只打算支持Windows (而不是Mono)呢?

如果是的话,有没有办法强迫我的程序以正常的双精度运行?

如果没有,是否有任何库可以帮助保持浮点计算的一致性?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2011-07-13 21:33:34

我不知道如何使.net中的普通浮点数具有确定性。允许JITter创建在不同平台(或不同版本的.net之间)上行为不同的代码。因此,在确定性的float代码中使用普通.net是不可能的。

我考虑过的解决办法是:

  1. 在FixedPoint32中实现C#。虽然这并不太难(我已经完成了一半的实现),但是非常小的值范围使得使用起来很烦人。你必须时刻小心,这样你就不会溢出,也不会失去太多的精确性。最后,我发现这并不比直接使用整数容易。
  2. 在FixedPoint64中实现C#。我发现这件事很难做。对于某些操作,128位的中间整数将是有用的。但是.net不提供这样的类型。
  3. 实现自定义32位浮点。缺乏BitScanReverse内在特性会在实现这一点时引起一些烦恼。但目前我认为这是最有希望的道路。
  4. 对数学操作使用本机代码。每个数学操作都会产生委托调用的开销。

我刚刚开始了32位浮点数学的软件实现。在2.66GHz的i3上,它每秒可以完成大约7000万次的加法/乘法运算。https://github.com/CodesInChaos/SoftFloat。很明显,它还很不完整,而且充满了问题。

票数 55
EN

Stack Overflow用户

发布于 2011-07-13 21:44:37

C#规范(§4.1.6浮点类型)特别允许使用高于结果的精度进行浮点计算。所以,不,我不认为你可以让这些计算直接在.Net中确定。其他人提出了各种解决办法,这样你就可以尝试它们了。

票数 28
EN

Stack Overflow用户

发布于 2011-07-13 19:41:45

在需要这些操作的绝对可移植性的情况下,下面的页面可能很有用。讨论了IEEE 754标准的测试实现软件,包括模拟浮点操作的软件。然而,大多数信息可能是特定于C或C++的。

http://www.math.utah.edu/~beebe/software/ieee/

--关于不动点的一点注记

二进制不动点数字也可以很好地代替浮点,这从四个基本算术运算中可以看出:

  • 加法和减法都是微不足道的。它们的工作方式和整数一样。只是加或减!
  • 要乘两个不动点数,将这两个数字相乘,然后右移定义的小数位数。
  • 若要除以两个不动点数,请将红利移除所定义的小数位数,然后除以除数。
  • “哈坦加迪”(2007年)第四章对实现二元不动点数提供了额外指导(S.K. Hattangady,"DSP分块浮点间隔ALU的研制及控制应用",北卡罗莱纳州立大学硕士论文,2007年)。

二进制不动点数字可以在任何整数数据类型上实现,如int、long和BigInteger,以及不兼容CLS的类型uint和ulong。

正如在另一个答案中所建议的,您可以使用查找表,其中表中的每个元素都是二进制不动点数,以帮助实现复杂的函数,如正弦、余弦、平方根等等。如果查找表的粒度小于不动点数,则建议将查找表的粒度的一半添加到输入中,从而绕过输入:

代码语言:javascript
运行
复制
// Assume each number has a 12 bit fractional part. (1/4096)
// Each entry in the lookup table corresponds to a fixed point number
//  with an 8-bit fractional part (1/256)
input+=(1<<3); // Add 2^3 for rounding purposes
input>>=4; // Shift right by 4 (to get 8-bit fractional part)
// --- clamp or restrict input here --
// Look up value.
return lookupTable[input];
票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6683059

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档