python浮点错误

时间:2012-03-16 17:07:47

标签: python loops floating-point

我遇到了一个使用Python浮点错误的问题。我虽然在这里提一下可能有用。

我有一个外部采样系统,可记录5000Hz的数据。为了获得时间戳,我需要初始时间,然后添加(1.0 / 5000)以获取连续样本的时间戳。我很快注意到当前时间(time.time())偏离了使用循环时的计算时间。只是做简单的计算没有明显的漂移 - 一些代码:

start_time = time.time()
start_time_test = start_time
#get 512 samples - takes 512*1.0/5000 seconds
for i in arange(512):
   start_time = start_time + (1.0/5000) #5khz

 start_time_test = start_time_test + 512*(1.0/5000)
 print time.time() - start_time_test #no drift
 print time.time() - start_time # drifts
 print start_time_test - start_time # constant increment

现在,start_time_test和start_time之间的区别并不显着 - 每块512块大约是1.69e-5,非常快速地开始加起来。我很惊讶浮点错误在这里发挥作用。我将在这里研究使用十进制pacakge来限制错误。

是否会出现此级别的浮点错误? - 请注意,我可能做的事情很愚蠢,而且不是浮点错误。

3 个答案:

答案 0 :(得分:4)

a=time.time()
(a+1/5000.0)-a
#0.00020003318786621094
1/5000.0
#0.0002
1331918373+1/5000.0-1331918373
#0.00020003318786621094

时间浮点大于1/5000,所以当你加上10 ^ 9 + 2 ^ -4时,2 ^ -4部分会失去精度。

答案 1 :(得分:0)

1.0 / 5000.0没有终止二进制表示。如果您使用1.0 / 4096.0进行相同的实验,则会得到零差异。但是,在您的测试中,您使用每个打印调用time.time(),time.time()每次都会产生不同的结果。如果你想看看你选择分母时会遇到的数值问题,可以从图片中获取time.time()。对于您的示例,我得到8.743e-16的累积误差。

关于time.time()是一个大数字的点,因此通过添加小数字而失去精度是一个正确的一般观察。但是,我不认为这是这种情况的罪魁祸首。请考虑以下代码:

import time
for dt in [5000.0, 2096.0]:
    start = time.time()
    add = start
    for i in range(512):
        add += 1.0/dt
    mult = start + 512.0/dt
    diff = abs(add - mult)
print "dt:%s, add:%s, mult:%s, diff:%s" % (dt, add, mult, diff)

这会产生以下结果:

dt:5000.0,地址:1332070890.23 mult:1332070890.23,diff:1.69277191162e-05

dt:4096.0,地址:1332070890.25 mult:1332070890.25,diff:0.0

答案 2 :(得分:0)

我测试过,如果在这种情况下向一个小数字添加一个大数字是罪魁祸首。答案是“否”,双精度具有足够的有效数字,因此偏移量不需要增长。

原因是一个常见的诱饵陷阱,在数值求积中已知,并在Forman S. Acton的“Real computing made real”第145页中提到

这是怎么回事:第一次近似非常好。你得到一个3.3E-8的非常小的错误。但是你总结了错误:

错误2是6.6E-8。

错误3是1E-7

错误6是2E-7

错误30是1E-6

错误300是1E-5

错误512是1.6927719116210938E-5

以最佳精度计算时间戳的正确方法:

for i in arange(512):
 time_stamp = time_stamp_start + i/5000.0;

它还有一个好处,即实际值和计算值之间的差异不是持续增长的误差,而是具有类似随机的差异并被抵消。