将time.time()强制转换为float32时出现意外行为

时间:2017-12-08 14:45:54

标签: python numpy precision floating-accuracy

我想将一个纪元时间数组存储为dtype32的numpy数组。我希望失去准确性,但不会有30秒的差异!

np.float64(np.float32((time.time()))) - time.time()

有人可以解释发生了什么吗?如何将纪元时间存储为float32而不会丢失准确度?

1 个答案:

答案 0 :(得分:3)

自纪元以来的秒数是一个很大的数字。目前,它约为1.5e9。在此范围内,您将获得10秒内的精度误差。

首先,你要两次调用time.time(),这会加剧时间差 - 这些方法显然需要时间来调用。查看错误的更好方法是存储时间:

>>> import time
>>> import numpy as np
>>> t = time.time()
>>> np.float32(t) - t
62.610707998275757

您可以通过从numpy获取字符串表示来查看存储的实际十进制数:

>>> t
1512746305.389292
>>> np.float32(t).astype(str)
'1512746368.0'

记住,数字不是一点 - 只有0和1是比特。在32位浮点数中,您将数字以科学计数法存储,但以二进制形式存储。这会导致准确度下降。可表示为32位浮点数的值范围为-3.4e38到+ 3.4e38。有2 ^ 32个数字可以用32位表示...很明显,你在32位浮动范围内丢失了大量(无限多个......)可能的数字。

有两个超级简单的解决方案。

首先,如果您不关心亚秒......那么只需将其存储为整数。大纪元的时间甚至不会达到32位,直到2038年。(2037年SO用户的问候,担心Year 2038 Problem。维基百科仍然是一个东西吗?)

>>> np.int32(t) - t
-0.38929200172424316

当然,如果你想要更多的十进制精度...在转换为int之前乘以10,或100或1000。好吧,你可以累积错误,但是使用64位浮点数你应该没问题。

处理这个问题的第二种方法是只存储一个新的纪元时间,并根据你想要保存在数组中的时间来区分。这些较小数字的误差将远远小于十进制范围。

>>> new_epoch = time.time()
>>> t = time.time() - new_epoch
>>> np.float32(t) - t
-2.384185791015625e-07

然后只需将new_epoch保存在64位荣耀中,同时保存32位浮点数组,以便知道如何转换回来。

但是,请注意Python time module docs

  

即使时间总是作为浮点数返回,但并非所有系统都提供的精度超过1秒。

此外,我强烈推荐David Goldberg的着名文章What every computer scientist should know about floating-point arithmetic。即使只是前几页也能很好地概述浮点运算以及如何计算近似误差的大小!