我想我理解浮点数中的精度意味着什么,因为您只能依赖尾数中存储的内容。
如果我理解正确,如果您将 0.000001 100000 次加到 0,则可能会开始出现错误。
有没有办法通过在 32 位浮点数中使用更少的数字来防止此错误、预测它或减轻它?
编辑:例如,在星际争霸 2 中,仅传达单位命令,而不传达游戏状态。仍然所有玩家都认为同样的事情。浮点错误的累积是可以避免的,但是如何,以什么成本或约束?
我想我理解浮点数中的精度意味着什么,因为您只能依赖尾数中存储的内容。
如果我理解正确,如果您将 0.000001 100000 次加到 0,则可能会开始出现错误。
有没有办法通过在 32 位浮点数中使用更少的数字来防止此错误、预测它或减轻它?
编辑:例如,在星际争霸 2 中,仅传达单位命令,而不传达游戏状态。仍然所有玩家都认为同样的事情。浮点错误的累积是可以避免的,但是如何,以什么成本或约束?
当您在正确实现的浮点中执行单个操作并且舍入模式是舍入到最近(最常见)时,错误最多是可表示数字之间距离的一半。这是因为,在四舍五入模式下,运算返回最接近精确数学结果的可表示结果。(这称为“正确舍入”。)
这包括诸如将数字(例如“0.000001”或“1e-5”)转换为浮点数等操作。但是,某些操作,特别是用于复杂操作(如正弦或对数)的库例程,通常并不总是返回正确的舍入结果(由于这样做的困难)。因此,您必须在依赖错误界限之前检查您的实现规范。
32 位 IEEE 754 浮点使用一个符号位、八个指数位(表示从 -126 到 127 的正常指数 [of 2])和 23 个显式有效位。(专有名词是有效位。尾数是对数的小数部分。)完整有效位有 24 位,因为有一个隐含的前导位(次正规数除外,幅度低于 2 -126)。因此,一个可表示数字和下一个更高的可表示数字之间的距离是前一位的值的 2 -23倍。当然,该值是不大于该数字的 2 的最高幂。(例如,对于 5,前导位的值为 4,因此最低有效位的值为 4•2 -23 = 2 -21. 因此,如果单个操作的精确数学结果约为 5,则最大误差将为 2 -22。)
当您执行多个操作时,错误很大程度上取决于执行的操作和所涉及的值。必须进行仔细分析以确定误差范围。根据操作的不同,错误可能会合并并被放大,以至于错误甚至可以变得无限。
请注意,如果您尝试将 0.000001 相加 100,000 次,则会出现两种错误。首先,0.000001 不能完全用二进制浮点表示,因此将该数字转换为浮点的操作存在错误。其次,每次加法都可能有舍入误差。
您还提到在不同的流程中维护相同的信息。这是一个与边界误差分开但重叠的问题。如果进程在相同的平台上运行,那么保持它们同步可能并不难,方法是让它们都使用相同的数据、使用相同的硬件和库执行相同的操作。这是因为浮点错误通常不是随机的;对相同的数据执行相同的操作将始终返回相同的结果。(当硬件或库行为未完全指定并且允许依赖于不相关的数据时,可能会出现一些问题,尽管这往往是理论上的问题而不是实践中的问题。)请注意,相同的平台意味着完全相同。
如果进程在不同的平台上运行,则很难保持它们同步。即使使用从相同源编译的软件运行,编译器也可以使用不同的浮点运算选择来实现高级语言。其中最臭名昭著的是使用比高级语言要求更高的精度,这是某些语言所允许的。
IEEE 754-2008 标准的第 11 条包含有关生成可重现浮点结果的信息。计算平台可能无法提供必要的保证来支持这一点。
使用多精度浮点库(二进制或十进制取决于是否始终准确表示十进制常量对您很重要),或有理数的实现。
这就是数值稳定性的艺术。有一些基本原则,但在编程时记住它们并不总是那么容易。考虑求解一个二次方程的例子。
当您说“数字”时,您可能指的是十进制数字。首先要了解二进制浮点是它以二进制表示,并且它会导致混淆以十进制数字来思考。
为了更直接地回答那部分,隐藏一些精确度只会掩盖问题,并不能解决问题。这几乎总是一个坏主意。
关于您的星际争霸 2 示例,关于 IEEE 754 浮点的一个典型迷信是它不是确定性的,好像它可以在两台计算机上执行相同的计算(例如,网络游戏中的两个 StarCaft 2 客户端)给出不同的结果。好吧,IEEE 754 是确定性的。浮点计算与使用实数完成的相同计算略有不同,但对于两个连续运行或运行相同二进制文件的两台不同计算机,只要每台计算机上的处理器正确实现 IEEE 754,计算总是相同的标准(他们基本上是这样做的)。