Converting a float to a string without rounding it - python

I'm making a program that, for reasons not needed to be explained, requires a float to be converted into a string to be counted with len(). However, str(float(x)) results in x being rounded when converted to a string, which throws the entire thing off. Does anyone know of a fix for it?
Here's the code being used if you want to know:
len(str(float(x)/3))

Some form of rounding is often unavoidable when dealing with floating point numbers. This is because numbers that you can express exactly in base 10 cannot always be expressed exactly in base 2 (which your computer uses).
For example:
>>> .1
0.10000000000000001
In this case, you're seeing .1 converted to a string using repr:
>>> repr(.1)
'0.10000000000000001'
I believe python chops off the last few digits when you use str() in order to work around this problem, but it's a partial workaround that doesn't substitute for understanding what's going on.
>>> str(.1)
'0.1'
I'm not sure exactly what problems "rounding" is causing you. Perhaps you would do better with string formatting as a way to more precisely control your output?
e.g.
>>> '%.5f' % .1
'0.10000'
>>> '%.5f' % .12345678
'0.12346'
Documentation here.

len(repr(float(x)/3))
However I must say that this isn't as reliable as you think.
Floats are entered/displayed as decimal numbers, but your computer (in fact, your standard C library) stores them as binary. You get some side effects from this transition:
>>> print len(repr(0.1))
19
>>> print repr(0.1)
0.10000000000000001
The explanation on why this happens is in this chapter of the python tutorial.
A solution would be to use a type that specifically tracks decimal numbers, like python's decimal.Decimal:
>>> print len(str(decimal.Decimal('0.1')))
3

Other answers already pointed out that the representation of floating numbers is a thorny issue, to say the least.
Since you don't give enough context in your question, I cannot know if the decimal module can be useful for your needs:
http://docs.python.org/library/decimal.html
Among other things you can explicitly specify the precision that you wish to obtain (from the docs):
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
A simple example from my prompt (python 2.6):
>>> import decimal
>>> a = decimal.Decimal('10.000000001')
>>> a
Decimal('10.000000001')
>>> print a
10.000000001
>>> b = decimal.Decimal('10.00000000000000000000000000900000002')
>>> print b
10.00000000000000000000000000900000002
>>> print str(b)
10.00000000000000000000000000900000002
>>> len(str(b/decimal.Decimal('3.0')))
29
Maybe this can help?
decimal is in python stdlib since 2.4, with additions in python 2.6.
Hope this helps,
Francesco

I know this is too late but for those who are coming here for the first time, I'd like to post a solution. I have a float value index and a string imgfile and I had the same problem as you. This is how I fixed the issue
index = 1.0
imgfile = 'data/2.jpg'
out = '%.1f,%s' % (index,imgfile)
print out
The output is
1.0,data/2.jpg
You may modify this formatting example as per your convenience.

Related

Can Decimal('5E+1') be simply converted to Decimal('50') in Python?

Context
We display percentage values to agents in our app without trailing zeros (50% is much easier to quickly scan than is 50.000%), and hitherto we've just used quantize to sort of brute force normalize the value to remove trailing zeros.
This morning I decided to look into using Decimal.normalize instead, but ran into this:
Given the decimal value:
>>> value = Decimal('50.000')
Normalizing that value:
>>> value = value.normalize()
Results in:
>>> value
Decimal('5E+1')
I understand the value is the same:
>>> Decimal('5E+1') == Decimal('50')
True
But from a non-technical user's perspective, 5E+1 is basically meaningless.
Question
Is there a way to convert Decimal('5E+1') to Decimal('50')?
Note
I'm not looking to do anything that would change the value of the Decimal (e.g., removing decimal places altogether), since the value could be e.g., Decimal('33.333'). IOW, don't confuse my 50.000 example as meaning that we're only dealing with whole numbers.
For the purposes of output formatting, you can print your normalized Decimal objects with the f format specifier. (While the format string docs say this defaults to a precision of 6, this does not appear to be the case for Decimal objects.)
>>> print('{:f}%'.format(decimal.Decimal('50.000').normalize()))
50%
>>> print('{:f}%'.format(decimal.Decimal('50.003').normalize()))
50.003%
>>> print('{:f}%'.format(decimal.Decimal('1.23456789').normalize()))
1.23456789%
If for some reason, you really want to make a new Decimal object with different precision, you can do that by just calling Decimal on the f format output, but it sounds like you're dealing with an output format problem, not something you should change the internal representation for.
>>> Decimal('{:f}'.format(Decimal('5E+1')))
Decimal('50')
>>>
>>> Decimal('{:f}'.format(Decimal('50.000').normalize()))
Decimal('50')
>>> Decimal('{:f}'.format(Decimal('50.003').normalize()))
Decimal('50.003')
>>> Decimal('{:f}'.format(Decimal('1.23456789').normalize()))
Decimal('1.23456789')
according to the python 3.9 docs the below is how to do it - https://docs.python.org/3.9/library/decimal.html#decimal-faq
def remove_exponent(d):
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
Add Decimal(0) to your result.
Decimal('50.000').normalize()
# Decimal('5E+1')
Decimal('50.000').normalize() + Decimal(0)
# Decimal('50')

How to place a number in the middle of string using python?

suppose a float number x=3.1234. I want to print this number in the middle of the string containing space in the left side and right side of x. string length will be variable. Precision of x will be variable. if string length=10 and precision=2 the output will be " 3.14 " Have any function in python that can return this?
This is really nicely documented at https://docs.python.org/3.6/library/string.html#format-specification-mini-language
But since you clearly didn't have time to google for it:
>>> x = 3.1234
>>> length=10
>>> precision=2
>>> f"{x:^{length}.{precision}}"
' 3.1 '
I'm afraid your notion of precision doesn't agree with Python's in the default case. You can fix it by specifying fixed point formatting instead of the default general formatting:
>>> f"{x:^{length}.{precision}f}"
' 3.12 '
This notation is more perspicuous than calling the method str.format(). But in Python 3.5 and earlier you need to do this instead:
>>> "{x:^{length}.{precision}f}".format(x=x, length=length, precision=precision)
But no amount of fiddling with the format is going to make 3.1234 come out as 3.14. I suspect that that was an error in the question, but if you really meant it, then there is no alternative but adjust the value of x before formatting it. Here is one way to do that:
>>> from decimal import *
>>> (Decimal(x) / Decimal ('0.02')).quantize(Decimal('1'), rounding=ROUND_UP) * Decimal('0.02')
Decimal('3.14')
This divides your number into a whole number of chunks of size 0.02, rounding up where necessary, then multiplies by 0.02 again to get the value you want.

Can I change Python's Decimal default formatting?

I'm working with Python Decimal types, up to 8 decimal places, and for very small numbers, by default, they are displayed using exponential notation. I would prefer them to be displayed in non exponential notation. Example follows:
>>> from decimal import Decimal
>>> d1 = Decimal('0.00000100')
>>> d1
Decimal('0.00000100')
>>> str(d1)
0.00000100
In this case, d1 does just what I'd like. But if I use another with a slightly smaller number, I get exponent notation:
>>> d2 = Decimal('0.00000001')
>>> d2
Decimal('1E-8')
>>> str(d2)
'1E-8'
I realise that I can format this using format(d2, 'f') but there are lots of places where these values are passed directly to the front end of my app using an API so I'd rather not if possible.
I'm curious to know if this is something I can change?
Thanks!
No, you cannot. If you really need to do this, you have following 2 options:
If you keep your Decimals with two digits of precision, then converting them to strings with str will work fine.
As suggested in the question, use format()
Source: Python Decimal Documentation

Python 3.0+ setting to max 4 decimal and rounding

So I have an assignment to match an expected output: 34.7381. But I am getting 34.73809999999999. I realize that it is just a rounded number with only 4 decimal places but I have no clue how to that in a short step.
I could brute force it and check for the placement of the decimal point, checking how many characters are after it, eliminating all of them and doing the rounding myself. But that seems rather complicated and stupid for something so simple.
Thanks you for your help!
Have you tried round function?
a = 34.73809999999999
print round(a, 4)
>>> 34.7381
You can use string formatting:
>>> '{:0.4f}'.format(34.7381)
'34.7381'
>>> '{:0.4f}'.format(34.73809999999999)
'34.7381'
Don't worry about it, and just specify the precision you want in your printing:
>>> print('{:.4f}'.format(34.73809999999999))
34.7381

"rounding" a negative exponential in python

I am looking to convert some small numbers to a simple, readable output. Here is my method but I wondering if there is something simpler.
x = 8.54768039530728989343156856E-58
y = str(x)
print "{0}.e{1}".format(y.split(".")[0], y.split("e")[1])
8.e-58
This gets you pretty close, do you need 8.e-58 exactly or are you just trying to shorten it into something readable?
>>> x = 8.54768039530728989343156856E-58
>>> print "{0:.1e}".format(x)
8.5e-58
An alternative:
>>> print "{0:.0e}".format(x)
9e-58
Note that on Python 2.7 or 3.1+, you can omit the first zero which indicates the position, so it would be something like "{:.1e}".format(x)
like this?
>>> x = 8.54768039530728989343156856E-58
>>> "{:.1e}".format(x)
'8.5e-58'
Another way of doing it, if you ever want to extract the exponent without doing string manipulations.
def frexp_10(decimal):
logdecimal = math.log10(decimal)
return 10 ** (logdecimal - int(logdecimal)), int(logdecimal)
>>> frexp_10(x)
(0.85476803953073244, -57)
Format as you wish...
There are two answers: one for using the number and one for simple display.
For actual numbers:
>>> round(3.1415,2)
3.14
>>> round(1.2345678e-10, 12)
1.23e-10
The built-in round() function will round a number to an arbitrary number of decimal places. You might use this to truncate insignificant digits from readings.
For display, it matters which version of display you use. In Python 2.x, and deprecated in 3.x, you can use the 'e' formatter.
>>> print "%6.2e" % 1.2345678e-10
1.23e-10
or in 3.x, use:
>>> print("{:12.2e}".format(3.1415))
3.14e+00
>>> print("{:12.2e}".format(1.23456789e-10))
1.23e-10
or, if you like the zeros:
>>> print("{:18.14f}".format(1.23456789e-10))
0.00000000012346

Categories

Resources