使用浮点数时避免不准确?
Avoiding inaccuracy when using floating points numbers?
我正在尝试使用 Monte Carlo 积分来近似给定图形下的区域以计算其面积。为此,我需要计算出的 y_min 和 y_max 是准确的。因此,作为示例,我将使用从 0 到 pi 的 sin(x)
图表。要找到 y_min 和 y_max 我有以下功能:
def y_range(f, x_min, x_max, n=100):
# Step size
h = float((x_max - x_min)) / n
# Calculate y for n points between x_min and x_max
y = [f(x * h) for x in range(0, n + 1)]
# Get minimum and maximum y
y_max = max(y)
y_min = min(y)
return y_min, y_max
打印 y_min 和 y_max 得到:
y_max = 1.0
y_min = -3.21624529935e-16
我知道 y_min 应该等于 0.0,那么我该如何纠正这个错误?
当精度如此重要时,我不会使用 float
。我建议你看看decimal.Decimal
。假设您将 x_min
和 x_max
更改为 Decimal,您只需删除第 3 行的 float
。
This post 可能有助于解释不准确的来源:
pi 是不合理的,因此无论您使用哪种表示方式,您都必须接受它只能以一定的精度表示。如果您使用的是浮点数,那么精度将按照 10**(-16)
的顺序排列 here。最简单的方法是使用 round(value,15)
将结果四舍五入为 15 位小数。如果您需要比 15 位十进制数字更高的精度,您确实可以研究其他类型来表示变量,例如 decimal
根本问题是 max
不能作为 min + 100*h
的结果导出,对于任何 h
。有几个潜在的原因,但最直接的一个就是它们之间的步数不能被 100
整除。
如何做得更好取决于你想要多小心。您需要做的两件事是在两个值之间进行插值(而不是基于起点和步骤),并以准确的方式执行插值本身。
以下代码将产生可靠的结果:
def interp_at_step(a, b, i, n):
# separate calculation of alpha and beta to avoid catastrophic cancellation
alpha = (n-i)/n
beta = i/n
return a*alpha + b*beta
def y_range(f, x_min, x_max, n=100):
# Calculate y for n points between x_min and x_max
y = [f(interp_at_step(x_min, x_max, x, n)) for x in range(0, n + 1)]
# Get minimum and maximum y
y_max = max(y)
y_min = min(y)
return y_min, y_max
当然,正如 Denys 提到的,pi 不能精确表示。因此,这将减少插值的错误,但不一定会减少操作数本身的错误。
我正在尝试使用 Monte Carlo 积分来近似给定图形下的区域以计算其面积。为此,我需要计算出的 y_min 和 y_max 是准确的。因此,作为示例,我将使用从 0 到 pi 的 sin(x)
图表。要找到 y_min 和 y_max 我有以下功能:
def y_range(f, x_min, x_max, n=100):
# Step size
h = float((x_max - x_min)) / n
# Calculate y for n points between x_min and x_max
y = [f(x * h) for x in range(0, n + 1)]
# Get minimum and maximum y
y_max = max(y)
y_min = min(y)
return y_min, y_max
打印 y_min 和 y_max 得到:
y_max = 1.0
y_min = -3.21624529935e-16
我知道 y_min 应该等于 0.0,那么我该如何纠正这个错误?
当精度如此重要时,我不会使用 float
。我建议你看看decimal.Decimal
。假设您将 x_min
和 x_max
更改为 Decimal,您只需删除第 3 行的 float
。
This post 可能有助于解释不准确的来源:
pi 是不合理的,因此无论您使用哪种表示方式,您都必须接受它只能以一定的精度表示。如果您使用的是浮点数,那么精度将按照 10**(-16)
的顺序排列 here。最简单的方法是使用 round(value,15)
将结果四舍五入为 15 位小数。如果您需要比 15 位十进制数字更高的精度,您确实可以研究其他类型来表示变量,例如 decimal
根本问题是 max
不能作为 min + 100*h
的结果导出,对于任何 h
。有几个潜在的原因,但最直接的一个就是它们之间的步数不能被 100
整除。
如何做得更好取决于你想要多小心。您需要做的两件事是在两个值之间进行插值(而不是基于起点和步骤),并以准确的方式执行插值本身。
以下代码将产生可靠的结果:
def interp_at_step(a, b, i, n):
# separate calculation of alpha and beta to avoid catastrophic cancellation
alpha = (n-i)/n
beta = i/n
return a*alpha + b*beta
def y_range(f, x_min, x_max, n=100):
# Calculate y for n points between x_min and x_max
y = [f(interp_at_step(x_min, x_max, x, n)) for x in range(0, n + 1)]
# Get minimum and maximum y
y_max = max(y)
y_min = min(y)
return y_min, y_max
当然,正如 Denys 提到的,pi 不能精确表示。因此,这将减少插值的错误,但不一定会减少操作数本身的错误。