python浮点错误

python浮点错误,python,loops,floating-point,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/5

我在使用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
现在,开始时间测试和开始时间之间的差异并不是微不足道的——它大约是每512块1.69e-5,这很快开始累积。我只是对浮点错误很快就在这里起作用感到惊讶。我将在这里研究使用十进制包装来限制错误


是否预期会出现此级别的浮点错误?-请不要说我可能在做一些愚蠢的事情,这不是浮点错误。

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,add:1332070890.23 mult:1332070890.23,差异:1.69277191162e-05


dt:4096.0,add:1332070890.25 mult:1332070890.25,diff:0.01.0/5000.0没有终止二进制表示。如果你用1.0/4096.0做同样的实验,你会得到一个零的差值。但是,在测试中,每次打印都调用time.time(),而time.time()每次都会产生不同的结果。如果您想了解在选择分母时遇到的数值问题,请从图片中获取time.time()。我得到了8.743e-16的累积误差

a=time.time()
(a+1/5000.0)-a
#0.00020003318786621094
1/5000.0
#0.0002
1331918373+1/5000.0-1331918373
#0.00020003318786621094
关于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,add:1332070890.23 mult:1332070890.23,差异:1.69277191162e-05

dt:4096.0,添加:1332070890.25多个:1332070890.25,差异:0.0

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/5000,因此当您添加10^9+2^-4时,2^-4部分会失去精度。

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

原因是一个常见的诱杀装置,在数值求积中已知,并在Forman S.Acton的“Real computing Make 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;

它的另一个好处是,实际值和计算值之间的差异不是不断增长的误差,而是随机性的差异,并相互抵消。

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

原因是一个常见的诱杀装置,在数值求积中已知,并在Forman S.Acton的“Real computing Make 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;

它的另一个好处是,实际值和计算值之间的差异不是持续增长的误差,而是具有随机性差异,并相互抵消。

Ok fine-这是预期的漂移水平吗?没有什么新鲜事-你可能想使用for循环中的计算会出现1.7e-5的浮点误差吗?@RossW是的,我会,因为1/5000不是完全可表示的,并且在
start\u time
和1/5000之间会有很大的幅度差异,这会加剧舍入。归结起来就是这由于这两个数字的大小相同,因此可以高精度地计算
1/5000+1/5000
。但是如果您尝试
10000000+1/5000
,您会发现错误要大得多,因为精度都被较大数字的有效位消耗掉了。在代码中,您应该从0开始执行求和,然后在循环完成后将求和值添加到
start\u time
。既然我理解了你的问题,我希望这能帮上一点忙。好吧,这是预期的漂移水平吗?没有什么新鲜事-你可能想使用for循环中的计算会出现1.7e-5的浮点误差吗?@RossW是的,我会,因为1/5000不是完全可表示的,并且在
start\u time
和1/5000之间会有很大的幅度差异,这会加重