我正在维护一个使用Python脚本 xlrd 从Excel电子表格中检索值,然后与它们一起做各种事情。电子表格中的某些单元格是高精度的数字,必须保留。检索其中一个细胞的值时, xlrd 给我一个 float 例如0.3828746115497402。

但是,我需要在代码中的以后将此值放入字符串中。都做 str(value) 或者 unicode(value) 将返回“ 0.382887461155”之类的东西。要求说这是不可接受的;需要保留精度。

到目前为止,我尝试过几件事都没有成功。首先是使用字符串格式化的东西:

data = "%.40s" % (value) 
data2 = "%.40r" % (value) 

但两者都产生相同的圆形数字,“ 0.382887461155”。

在搜索SO和Internet上其他地方有类似问题的人时,一个普遍的建议是使用 Decimal 班级。但是我无法更改数据的方式(除非有人知道一种秘密方法 xlrd 返回小数)。当我尝试这样做时:

data = Decimal(value)

我得到一个 TypeError: Cannot convert float to Decimal. First convert the float to a string. 但是显然我无法将其转换为字符串,否则我会失去精度。

所以,是的,我对任何建议都开放 - 如有必要,即使是非常粗略的建议。我对Python(我本人更多是Java/c#家伙)的经验并不多,因此,如果我在这里有某种根本的误解,请随时纠正我。

编辑:只是以为我会补充说我正在使用Python 2.6.4。我认为没有任何正式要求阻止我更改版本。它只需要弄乱其他任何代码即可。

有帮助吗?

解决方案

我是XLRD的作者。其他答案和评论在评论中有很多混乱,因此我在答案中做到了。

@katriealex:“”“ XLRD“”“” ---完全没有根据和不真实。 XLRD精确地重现了XLS文件中存储的64位浮点。

@katriealex:“”“可能可以修改您的本地XLRD安装以更改float cast“”“ ----我不知道为什么要这样做;浮动16位整数不会失去任何精度!!!在任何情况下,仅在读取Excel 2.x文件(具有整数型单元格记录)时使用代码。 OP没有迹象表明他正在阅读此类古老的文件。

@Jloubert:您一定会误会。 "%.40r" % a_float 只是一种巴洛克式的方式,可以获得与 repr(a_float).

@EveryBody:您无需将浮子转换为十进制即可保持精度。全部 repr() 功能是保证以下内容:

float(repr(a_float)) == a_float

python 2.x(x <= 6)reper给出了精确的常数17个小数位数,因为可以保证重现原始值。后来的Python(2.7,3.1)给出了将重现原始值的十进制数字。

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.38288746115497402'
>>> float(repr(f)) == f
True

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.382887461154974'
>>> float(repr(f)) == f
True

所以最重要的是 如果要保留浮子对象的所有精度的字符串,请使用 preserved = repr(the_float_object) ...以后恢复值 float(preserved). 这很简单。不需要 decimal 模块。

其他提示

您可以使用 repr() 要转换为字符串而不会丢失精度,然后转换为十进制:

>>> from decimal import Decimal
>>> f = 0.38288746115497402
>>> d = Decimal(repr(f))
>>> print d
0.38288746115497402

编辑:我错了。我将在此处留下这个答案,以便其余的线程有意义,但事实并非如此。请参阅上面的John Machin的答案。谢谢大家=)。

如果上述答案很棒 - 它将为您节省很多令人讨厌的黑客。但是,至少在我的系统上,它们不会。您可以使用EG进行检查

import sys
print( "%.30f" % sys.float_info.epsilon )

该数字是系统可以区分零的最小浮点。执行操作时,可能会随机添加或从任何浮标中随机添加或减去任何较小的东西。 这意味着,至少在我的python设置中,精度在胆量中丢失了 xlrd, ,而且似乎无需修改它就无能为力。这很奇怪;我已经期望此案发生过,但显然不是!

可以修改您的本地 xlrd 安装以更改 float 投掷。打开 site-packages\xlrd\sheet.py 然后下达第1099行:

...
elif rc == XL_INTEGER:
                    rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
                    self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
...

注意 float 演员 - 您可以尝试将其更改为 decimal.Decimal 看看会发生什么。

编辑: 清除了我以前的答案b/c,它无法正常工作。

我在Python 2.6.5上,这对我有用:

a = 0.38288746115497402
print repr(a)
type(repr(a))    #Says it's a string

注意:这只是转换为字符串。您需要转换为 Decimal 如果需要的话,请以后。

正如已经说过的那样,浮子根本不精确 - 因此,保留精度可能会产生误导。

这是一种从浮点对象中获取所有最后一点信息的方法:

>>> from decimal import Decimal
>>> str(Decimal.from_float(0.1))
'0.1000000000000000055511151231257827021181583404541015625'

另一种方式就是这样。

>>> 0.1.hex()
'0x1.999999999999ap-4'

这两个字符串代表浮子的确切内容。除了Python认为它的意图(大多数情况下是正确的),其他所有内容都可以解释浮子。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top