Python/numpy浮点文本精度

jte*_*ace 2 python floating-point precision numpy

假设我有一些32位和64位浮点值:

>>> import numpy as np
>>> v32 = np.array([5, 0.1, 2.4, 4.555555555555555, 12345678.92345678635], 
                   dtype=np.float32)
>>> v64 = np.array([5, 0.1, 2.4, 4.555555555555555, 12345678.92345678635], 
                   dtype=np.float64)
Run Code Online (Sandbox Code Playgroud)

我想将这些值序列化为文本而不会丢失精度(或者至少非常接近于不会丢失精度).我认为这样做的规范方法是repr:

>>> map(repr, v32)
['5.0', '0.1', '2.4000001', '4.5555553', '12345679.0']
>>> map(repr, v64)
['5.0', '0.10000000000000001', '2.3999999999999999', '4.5555555555555554', 
 '12345678.923456786']
Run Code Online (Sandbox Code Playgroud)

但是我希望尽可能简化表示以最小化文件大小,所以如果像2.4这样的值被序列化而没有额外的小数就会很好.是的,我知道这是他们实际的浮点表示,但%g似乎可以解决这个问题:

>>> ('%.7g ' * len(v32)) % tuple(v32)
'5 0.1 2.4 4.555555 1.234568e+07 '
>>> ('%.16g ' * len(v32)) % tuple(v64)
'5 0.1 2.4 4.555555555555555 12345678.92345679 '
Run Code Online (Sandbox Code Playgroud)

我的问题是:%g以这种方式使用是否安全?是.7.16正确的值,以便不会丢失精度?

use*_*342 7

Python 2.7及更高版本已经repr为浮点数提供了一个智能实现,打印为0.1 0.1.选择简短的输出优先于其他候选者,例如0.10000000000000001因为它是读取回Python时往返于完全相同浮点值的特定数字的最短表示.要使用此算法,请将64位浮点数转换为实际的Python浮点数,然后再将其移至repr:

>>> map(repr, map(float, v64))
['5.0', '0.1', '2.4', '4.555555555555555', '12345678.923456786']
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,结果是自然的数字上正确的.关于2.7/3.2的更多信息repr可以在What's New和Mark Dickinson 的精彩演讲中找到.

不幸的是,这个技巧不适用于32位浮点数,至少没有重新实现Python 2.7所使用的算法repr.


Dan*_*her 6

要唯一地确定IEEE-754格式的单精度(32位)浮点数,可能需要使用9(有效,即不以0开头,除非值为0)十进制数字,并且9位数是总是足够的.

对于双精度(64位)浮点数,可能需要17(有效)十进制数字,并且始终足够.

我不太确定如何%g指定格式,通过它的外观,它可以让表示以0(0.1)开头,因此精度的安全值将为.9.17.

如果你想最小化文件大小,写字节表示会产生一个小得多的文件,所以如果你能做到这一点,那就是你要走的路.