📜  比较浮点数时出现问题,以及如何正确比较它们?(1)

📅  最后修改于: 2023-12-03 15:11:01.526000             🧑  作者: Mango

比较浮点数时出现问题,以及如何正确比较它们?

问题描述

在计算机中,浮点数(floating point number)是一种用来表示实数的数值类型。但是,在比较浮点数时,有时会出现错误的结果,即使看起来相等的两个数,在比较时也可能被判定为不相等。这是因为浮点数在计算机中的存储方式有一定的限制,存在精度问题。这种精度问题会导致浮点数的比较具有不可传递性,即如果 $a > b$,$b > c$,但 $a$ 和 $c$ 可能会被认为是相等的,因为它们之间的差非常小。

问题原因

要理解这个问题,需要先了解浮点数在计算机中的存储方式。浮点数通常采用 IEEE 754 标准中的单精度或双精度格式来存储。

单精度格式:32 位二进制,符号位 1 位,指数位 8 位,尾数位 23 位。

双精度格式:64 位二进制,符号位 1 位,指数位 11 位,尾数位 52 位。

在这个格式中,浮点数被表示为 $(-1)^s \times m \times 2^e$,其中 $s$ 表示符号位(0 表示正数,1 表示负数),$m$ 表示尾数,$e$ 表示指数。由于尾数只有 23 或 52 位,在进行计算时,会丢失一些尾数的位数,导致误差的产生。

解决方法

为了避免比较浮点数时出现误差,可以采用以下方法:

方法1:使用绝对误差函数

判断两个数是否相等时,可以使用绝对误差函数(Absolute Error Function)来进行比较:

def absolute_error(a, b):
   return abs(a - b)

def equal(a, b, tolerance=1e-9): # tolerance 是我们自己定义的误差范围
    return absolute_error(a, b) < tolerance

这种方法的弊端是我们需要手动定义一个误差范围。

方法2:使用相对误差函数

相对误差函数(Relative Error Function)可以基于两个数的比例来判断它们是否相等。

def relative_error(a, b):
   return abs((a - b) / b)

def equal(a, b, tolerance=1e-9):
    return relative_error(a, b) < tolerance

这种方法的缺点是当 b 接近于 0 时,分母非常小,导致相对误差产生很大的偏差。所以在使用这种方法时,需要额外注意。

方法3:使用 numpy.allclose()

Numpy 提供了 allclose() 函数,可以用来判断两个数组(或者浮点数列表)是否相等。其中,我们可以设置误差范围和比较的方式(absolute 或者 relative)。

import numpy as np
a = 1.23
b = 1.23
np.allclose(a, b, rtol=1e-9, atol=1e-9)

这种方法相对简单并且快速,是比较通用的一种解决方式。

总结

在比较浮点数时,需要注意精度问题。为了避免误差,可以使用绝对误差函数或者相对误差函数进行比较,也可以使用 numpy 的 allclose() 函数来判断两个数是否相等。