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.
We can convert float to a string easily using str() function.
The most Pythonic way to convert a list of floats fs to a list of strings is to use the one-liner fs = [str(x) for x in fs] . It iterates over all elements in the list fs using list comprehension and converts each list element x to a string value using the str(x) constructor.
We can convert float to String in java using String. valueOf() and Float. toString() methods.
Double precision numbers have 53 bits (16 digits) of precision and regular floats have 24 bits (8 digits) of precision. The floating point type in Python uses double precision to store the values.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With