将Python Float转换为String而不会丢失精度 [英] Converting a Python Float to a String without losing precision

查看:9101
本文介绍了将Python Float转换为String而不会丢失精度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在维护一个Python脚本,使用 xlrd 从Excel电子表格中检索值,然后与它们进行各种操作。电子表格中的一些单元格是高精度数字,它们必须保持原样。当检索这些单元格之一的值时, xlrd 给我一个 float ,如0.38288746115497402。



但是,我需要在代码中稍后将此值转换为字符串。执行 str(value) unicode(value)将返回0.382887461155。要求说这是不能接受的;精度需要保留。



我已经尝试了几件事情,迄今没有成功。第一个是使用字符串格式化的东西:

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

但是两者都产生相同的舍入数,0.382887461155。



在SO和其他互联网上搜索有类似问题的人,一个常见的建议是使用 Decimal 类。但是我不能改变数据给我的方式(除非有人知道一个秘密的方法来使 xlrd 返回小数)。当我尝试这样做:

  data = Decimal(value)
/ pre>

我得到一个 TypeError:无法将float转换为Decimal。首先将浮点数转换为字符串。但显然我无法将其转换为字符串,否则我将失去精度。



那么是的,我可以接受任何建议 - 如果有必要的话,甚至是真的很笨。我对Python没有非常有经验(更多的是Java / C#的人),所以如果我在这里有一些根本的误解,可以随时更正我。



编辑:只是想我会补充说,我在使用Python 2.6.4。我不认为有任何正式的要求阻止我改变版本;它只是不要弄乱任何其他代码。

解决方案

我是xlrd的作者。在其他答案和评论中有很多混淆,以反驳评论,所以我在一个答案中做。



@katriealex:精度在勇气xlrd---完全没有根据和不真实。 xlrd正好再现存储在XLS文件中的64位浮点数。



@katriealex:可能会修改您的本地xlrd安装以更改浮点数我不知道你为什么要这样做?浮动16位整数就不会失去任何精度!在任何情况下,仅当读取Excel 2.X文件(其具有INTEGER型单元格记录)时才使用该代码。 OP没有指示他正在阅读这些古代文件。



@jloubert:你一定是错误的。 %。40r%a_float 只是一个巴洛克式的方式得到与 repr(a_float)相同的答案。 / p>

@EVERYBODY:您不需要将浮点数转换为十进制以保留精度。 repr()函数的整个观点是保证以下内容:

  float(repr(a_float))== a_float 

Python 2.X(X < = 6)repr给出一个17位十进制数字的精度,因为这样保证能够再现原始值。后来的Pythons(2.7,3.1)给出将重现原始值的最小数字的十进制数字。

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

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

所以底线是如果您想要一个保留浮点对象精度的字符串,请使用 preserve = repr(the_float_object) ...稍后通过 float(保留)很简单。不需要 decimal 模块。


I am maintaining a Python script that uses xlrd to retrieve values from Excel spreadsheets, and then do various things with them. Some of the cells in the spreadsheet are high-precision numbers, and they must remain as such. When retrieving the values of one of these cells, xlrd gives me a float such as 0.38288746115497402.

However, I need to get this value into a string later on in the code. Doing either str(value) or unicode(value) will return something like "0.382887461155". The requirements say that this is not acceptable; the precision needs to be preserved.

I've tried a couple things so far to no success. The first was using a string formatting thingy:

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

But both produce the same rounded number, "0.382887461155".

Upon searching around for people with similar problems on SO and elsewhere on the internet, a common suggestion was to use the Decimal class. But I can't change the way the data is given to me (unless somebody knows of a secret way to make xlrd return Decimals). And when I try to do this:

data = Decimal(value)

I get a TypeError: Cannot convert float to Decimal. First convert the float to a string. But obviously I can't convert it to a string, or else I will lose the precision.

So yeah, I'm open to any suggestions -- even really gross/hacky ones if necessary. I'm not terribly experienced with Python (more of a Java/C# guy myself) so feel free to correct me if I've got some kind of fundamental misunderstanding here.

EDIT: Just thought I would add that I am using Python 2.6.4. I don't think there are any formal requirements stopping me from changing versions; it just has to not mess up any of the other code.

解决方案

I'm the author of xlrd. There is so much confusion in other answers and comments to rebut in comments so I'm doing it in an answer.

@katriealex: """precision being lost in the guts of xlrd""" --- entirely unfounded and untrue. xlrd reproduces exactly the 64-bit float that's stored in the XLS file.

@katriealex: """It may be possible to modify your local xlrd installation to change the float cast""" --- I don't know why you would want to do this; you don't lose any precision by floating a 16-bit integer!!! In any case that code is used only when reading Excel 2.X files (which had an INTEGER-type cell record). The OP gives no indication that he is reading such ancient files.

@jloubert: You must be mistaken. "%.40r" % a_float is just a baroque way of getting the same answer as repr(a_float).

@EVERYBODY: You don't need to convert a float to a decimal to preserve the precision. The whole point of the repr() function is that the following is guaranteed:

float(repr(a_float)) == a_float

Python 2.X (X <= 6) repr gives a constant 17 decimal digits of precision, as that is guaranteed to reproduce the original value. Later Pythons (2.7, 3.1) give the minimal number of decimal digits that will reproduce the original value.

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

So the bottom line is that if you want a string that preserves all the precision of a float object, use preserved = repr(the_float_object) ... recover the value later by float(preserved). It's that simple. No need for the decimal module.

这篇关于将Python Float转换为String而不会丢失精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆