比较浮点数是否相等的几个原因是:
- 测试软件。给定的软件应该符合精确的规范,精确的结果可能是已知的或可计算的,因此测试程序会将主题软件的结果与预期结果进行比较。
- 执行精确算术。精心设计的软件可以执行精确的浮点运算。在最简单的情况下,这可能只是整数运算。 (在提供 IEEE-754 64 位双精度浮点但仅 32 位整数运算的平台上,浮点运算可用于执行 53 位整数运算。)在执行精确算术时比较相等是与用整数运算比较相等性相同。
- 搜索排序或结构化数据。浮点值可用作搜索的键,在这种情况下,需要进行相等性测试以确定已找到所查找的项目。 (如果 NaN 可能存在,则会出现问题,因为它们在任何顺序测试中都报告错误。)
- 避免极点和不连续性。函数在某些点上可能有特殊的行为,其中最明显的就是除法。软件可能需要针对这些点进行测试并将执行转移到其他方法。
请注意,当使用浮点算术逼近实数算术时,只有最后一个相等性测试。 (此示例列表不完整,因此我不希望这是唯一的此类用途。)前三个是特殊情况。通常在使用浮点算术时,一种是逼近实数算术并使用大部分连续函数。连续函数对于浮点运算来说是“可以的”,因为它们以“正常”的方式传输错误。例如,如果到目前为止您的计算产生了一些接近理想数学结果 a 的 a',而您有一个接近于理想数学结果的 b'一个理想的数学结果b,那么计算的总和a'+b'将近似于a+ b.
另一方面,不连续的函数会破坏这种行为。例如,如果我们尝试将一个数字四舍五入到最接近的整数,当 a 为 3.49 时会发生什么?我们的近似值 a' 可能是 3.48 或 3.51。计算舍入时,近似值可能会产生 3 或 4,将非常小的误差变成非常大的误差。在浮点运算中使用不连续函数时,必须小心。例如,考虑计算二次公式 (−b±sqrt(b2-4ac)) /(2a)。如果b2−4ac的计算过程中出现轻微错误,结果可能为负,然后sqrt会返回南。所以软件不能简单地使用浮点运算,就好像它很容易逼近实数运算一样。程序员必须了解浮点运算并警惕其中的陷阱,而这些问题及其解决方案可能因特定的软件和应用程序而异。
相等性测试是一个不连续的功能。它是一个函数 f(a, b),除了沿 a=b 线以外的所有地方都为 0。由于它是一个不连续的函数,它可以将小错误变成大错误——如果用理想数学计算,它可以报告为不相等的相等数,如果用理想数学计算,它可以报告为相等的不等数。
通过这个视图,我们可以看到相等性测试是一般函数类的成员。它并不比平方根或除法更特殊——它在大多数地方是连续的,但在某些地方是不连续的,因此必须小心使用它。这种护理是针对每个应用程序定制的。
我将介绍一个测试相等性非常有用的地方。我们实现了一些指定为忠实四舍五入的数学库例程。例程的最佳质量是正确舍入。考虑一个函数,其精确数学结果(对于特定输入 x)是 y。在某些情况下,y 可以精确地以浮点格式表示,在这种情况下,一个好的例程将返回 y。通常,y 不能完全表示。在这种情况下,它介于可以用浮点格式表示的两个数字之间,一些数字 y0 和 y1子>。如果例程正确舍入,则返回 y0 和 y1 中更接近 的那个是的。 (如果是平局,它会返回一个偶数低位的数字。另外,我只讨论从四舍五入到最近的平局模式。)
如果例程被忠实地四舍五入,则允许返回 y0 或 y1。
现在,这是我们想要解决的问题:我们有一些版本的单精度例程,比如 sin0,我们知道它是忠实四舍五入的。我们有一个新版本,sin1,我们想测试它是否忠实地四舍五入。我们有多精度软件,可以非常精确地评估数学 sin 函数,因此我们可以使用它来检查 sin1 的结果是否如实四舍五入。但是,多精度软件速度很慢,我们要测试所有 40 亿个输入。 sin0 和 sin1 都很快,但sin1 允许有与sin0 不同的输出,因为sin1 只需要忠实地四舍五入,而不是与sin0 相同。
但是,sin1 结果中大部分 与sin0 相同。 (这部分是数学库例程设计方式的结果,在使用一些最终算术运算来提供最终结果之前,使用一些额外的精度来获得非常接近的结果。这往往会得到正确舍入的结果大多数,但有时会滑到下一个最接近的值。)所以我们可以做的是:
- 对于每个输入,计算
sin0 和 sin1。
- 比较结果是否相等。
- 如果结果相同,我们就完成了。如果不是,请使用扩展精度软件测试
sin1 结果是否如实四舍五入。
同样,这是使用浮点运算的一种特殊情况。但它是平等测试非常有用的一种。最终的测试程序在几分钟而不是几个小时内运行。