为什么python在分割sin()的结果时会出现大错误

时间:2015-05-20 06:02:20

标签: python rounding-error

我试图找到我发现的等式的前十个整数输入的值:x = sin(2π / n) / sin(π / n)。我从我写的代码中得到的输出结果非常令人惊讶:

>>> for i in range(1, 11):
        print math.sin(2 * math.pi / i) / math.sin(math.pi / i)

-2.0
1.22464679915e-16
1.0
1.41421356237
1.61803398875
1.73205080757
1.8019377358
1.84775906502
1.87938524157
1.90211303259

我意识到会出现舍入错误,因此以下结果根本不会让我感到惊讶:

>>> math.sin(2 * math.pi)
-2.4492935982947064e-16
>>> math.sin(math.pi)
1.2246467991473532e-16

问题是,第一个结果是如何以-2.0结束的,我可能期望它返回接近于零或错误/纳米的东西?

如果你有兴趣知道,这个等式应该给出一条线的长度(x),该线在一个点和另一个点之间延伸2个点,形状有n个等边1和所有相等角度(长度)边长为1的isogon的最小对角线。

2 个答案:

答案 0 :(得分:3)

对于第二个结果,绝对值的影响非常小:1.22464679915e-16是一个非常小的数字,非常接近于零,约为0.00000000000000012246

如果您只是想避免对结果显示方式产生重大影响的小错误,请使用格式化字符串,例如:

for i in range(1, 11):
    print "{0:.10f}".format(math.sin(2 * math.pi / i) / math.sin(math.pi / i))

输出:

-2.0000000000
0.0000000000
1.0000000000
1.4142135624
1.6180339887
1.7320508076
1.8019377358
1.8477590650
1.8793852416
1.9021130326
  

第一个结果是如何以-2.0结束的,我可能期望它返回接近零或错误/纳米的东西?

第一个结果是当我为1时,它简化为:

math.sin(2 * math.pi) / math.sin(math.pi)

由于浮点错误,math.sin(2 * math.pi)评估为-2.44921270764e-16,而math.sin(math.pi)评估为1.22460635382e-16

-2.44921270764e-16 / 1.22460635382e-16的浮点除法给出了-2.0,因此它是最终输出。

在没有浮点错误的情况下,math.sin(2 * math.pi)math.sin(math.pi)都应该已经评估为零,但是浮点实现和Python sin函数实现的组合怪癖就是这样。第一个的浮点误差是第二个的两倍,而且是负的,所以将它们除以-2。

math.pi * 2的内部表示中的浮点错误是math.pi的两倍,因为当您使用错误边距加倍值时,错误边距也会加倍,并且无法表示pi作为没有一些错误的浮点数。猜测:该误差通过sin计算传播,并且由于sin计算中的某些事实引入了负数,这与pi到2 pi范围内的sin函数在0到0范围内的函数的负数有关。 PI。

如果要将极小值舍入为零,可以使用numpy.around舍入到给定的小数位数,例如:

import numpy
for i in range(1, 11):
    print numpy.around(numpy.sin(2 * numpy.pi / i), 15) / numpy.around(numpy.sin(numpy.pi / i), 15)

这为第一个结果产生了一个纳米。

答案 1 :(得分:2)

这些错误来自简单的浮点算术......这就是它的工作方式。所以,你可以避免使用浮点数,但这可能给你带来很大的痛苦。

如果你看一下浮点的工作原理here,你会发现错误会发生......很多。这基本上是大多数数据库支持定点精确度进行货币计算的原因。也就是说,固定点上的sin / cos会很痛苦......

避免这些错误的一种简单方法是对所有(或部分)180'使用简单的预先计算的查找表。 sin / cos的角度。