Problems with decimals and scientific notation in Python 2.6.6 - python

I'm having difficulty with decimal values that I need to use for arithmetic in some cases and as strings in others. Specifically I have a list of rates, ex:
rates=[0.1,0.000001,0.0000001]
And I am using these to specify the compression rates for images. I need to initially have these values as numbers because I need to be able to sort them to make sure they are in a specific order. I also want to be able to convert each of these values to strings so I can 1) embed the rate into the filename and 2) log the rates and other details in a CSV file. The first problem is that any float with more than 6 decimal places is in scientific format when converted to a string:
>>> str(0.0000001)
'1e-07'
So I tried using Python's Decimal module but it is also converting some floats to scientific notation (seemingly contrary to the docs I've read). Ex:
>>> Decimal('1.0000001')
Decimal('1.0000001')
# So far so good, it doesn't convert to scientific notation with 7 decimal places
>>> Decimal('0.0000001')
Decimal('1E-7')
# Scientific notation, back where I started.
I've also looking into string formatting as suggested in multiple posts, but I've not had any luck. Any suggestions and pointers are appreciated by this Python neophyte.

You have to specify the string format then:
["%.8f" % (x) for x in rates]
This yields ['0.10000000', '0.00000100', '0.00000010']. Works with Decimal, too.

'{0:f}'.format(Decimal('0.0000001'))
The above should work for you

See % formatting, especially the floating point conversions:
'e' Floating point exponential format (lowercase). (3)
'E' Floating point exponential format (uppercase). (3)
'f' Floating point decimal format. (3)
'F' Floating point decimal format. (3)
'g' Floating point format. Uses lowercase exponential format if exponent is less than -4 or not less than precision, decimal format otherwise. (4)
'G' Floating point format. Uses uppercase exponential format if exponent is less than -4 or not less than precision, decimal format otherwise. (4)
An example, using f format.
>>> ["%10.7f" %i for i in rates]
[' 0.1000000', ' 0.0000010', ' 0.0000001']
>>>
You can also use the newer (starting 2.6) str.format() method:
>>> ['{0:10.7f}'.format(i) for i in rates]
[' 0.1000000', ' 0.0000010', ' 0.0000001']
>>>

Using f-strings:
>>> rates = [0.1, 0.000001, 0.0000008]
>>> [f'{r:.7f}' for r in rates]
['0.1000000', '0.0000010', '0.0000008']
The string format {r:.7f} indicates the number of digits used after the decimal point, which in this case is 7.

Related

Why is Python truncating perfect float values? [duplicate]

I need to print or convert a float number to 15 decimal place string even if the result has many trailing 0s eg:
1.6 becomes 1.6000000000000000
I tried round(6.2,15) but it returns 6.2000000000000002 adding a rounding error
I also saw various people online who put the float into a string and then added trailing 0's manually but that seems bad...
What is the best way to do this?
For Python versions in 2.6+ and 3.x
You can use the str.format method. Examples:
>>> print('{0:.16f}'.format(1.6))
1.6000000000000001
>>> print('{0:.15f}'.format(1.6))
1.600000000000000
Note the 1 at the end of the first example is rounding error; it happens because exact representation of the decimal number 1.6 requires an infinite number binary digits. Since floating-point numbers have a finite number of bits, the number is rounded to a nearby, but not equal, value.
For Python versions prior to 2.6 (at least back to 2.0)
You can use the "modulo-formatting" syntax (this works for Python 2.6 and 2.7 too):
>>> print '%.16f' % 1.6
1.6000000000000001
>>> print '%.15f' % 1.6
1.600000000000000
The cleanest way in modern Python >=3.6, is to use an f-string with string formatting:
>>> var = 1.6
>>> f"{var:.15f}"
'1.600000000000000'
Floating point numbers lack precision to accurately represent "1.6" out to that many decimal places. The rounding errors are real. Your number is not actually 1.6.
Check out: http://docs.python.org/library/decimal.html
I guess this is essentially putting it in a string, but this avoids the rounding error:
import decimal
def display(x):
digits = 15
temp = str(decimal.Decimal(str(x) + '0' * digits))
return temp[:temp.find('.') + digits + 1]
We can use format() to print digits after the decimal places.
Taken from http://docs.python.org/tutorial/floatingpoint.html
>>> format(math.pi, '.12g') # give 12 significant digits
'3.14159265359'
>>> format(math.pi, '.2f') # give 2 digits after the point
'3.14'

how to round up the number for array format in .txt output i n python

I am trying to extract my analysis result in .txt file. The results show as below :
-3.298409999999999854e+04 -3.298409999999999854e+04
-3.297840000000000146e+04 -3.297840000000000146e+04
Code:
anodeIdx = [10,20,30]
stressAnodeXX = [x for i,x in enumerate(stress_xx[0].Y) if i in anodeIdx]
stressAnodeYY = [x for i,x in enumerate(stress_yy[0].Y) if i in anodeIdx]
np.savetxt('Stress_strain_Anode.txt',np.c_[stressAnodeXX,stressAnodeYY])
I expected the result to be -32984.1 but the actual output is -3.2984099999e+4
To save the number in a specific way, you can use optional parameter fmt of np.savetxt(). Documentation
In your case:
np.savetxt('Stress_strain_Anode.txt',np.c_[stressAnodeXX,stressAnodeYY], fmt='%.1f')
f is specifier wihch saves the number as decimal floating point.
.1 Represents how many decimal numbers should be after the decimal point.
I think the problem here is not the numbers not being rounded, but not being appropiately formatted.
You could use the fmt keyword argument of numpy.savetxt to solve this. (numpy documentation):
np.savetxt('Stress_strain_Anode.txt', np.c_[stressAnodeXX,stressAnodeYY], fmt='%.1f')
Where '%.1f' is a format string which formats numbers with one decimal digit.
Your result is actually -32984.1. Float representation in binary code is not ideal so you see it in a bit confusing way. If you want, you can just round your result (but it is not needed):
np.round(your_result_number, decimals=1)
which will return:
-32984.1
More about your result:
-3.2984099999e+4 has two confusing parts:
099999 in the end of number
e+4 in the end of output
e+4 is a scientific notation of your number. It means: "multiply it to 10^4=10000. If you will do it, you will get 3.29841 * 10000 = 32984.1
099999... in the end of the number appears because computer tries to represent decimal float number in binary code, which leads to small "errors". So your result is actually -32984.1.

can't get rid of 1e-5 while formatting in python 3 programming

I am creating a length calculator and need to format it so it doesn't show 1e-5 from going to mm to km. i have tried '{:.6}'.format() but doesn't seem to work as still outputs it as 1e-5.
Any help on what to do to get rid of this?
Use the f presentation type insteaf of the default (g with a small modification):
'{:.6f}'.format(floating_point_number)
See the Format Specification Mini-Language documentation:
'f'
Fixed point. Displays the number as a fixed-point number. The default precision is 6.
[...]
'g'
General format. For a given precision p >= 1, this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude.
[...]
None
Similar to 'g', except that fixed-point notation, when used, has at least one digit past the decimal point. The default precision is as high as needed to represent the particular value. The overall effect is to match the output of str() as altered by the other format modifiers.
Note that if all you are doing is formatting a float (and not include any other string in your str.format() template), you may as well avoid having to parse the template and use the format() function directly:
format(floating_point_number, '.6f')
Demo:
>>> fp = 1e-5
>>> fp
1e-05
>>> format(fp, '.6f')
'0.000010'
>>> '{:.6f}'.format(fp)
'0.000010'

What is the default rounding mode of string formatter in Python?

>>> '%f'%0.8407745
'0.840774'
>>> '%f'%0.8407755
'0.840776'
>>> '%f'%-0.8407755
'-0.840776'
>>> '%f'%-0.8407745
'-0.840774'
The results look weird. It is sometimes floor and sometimes ceil.
What is the default rounding mode of string formatter in Python?
Floating point numbers are always an approximation. 0.8407745 is not exactly 0.8407745:
>>> '%.53f' % 0.8407745
'0.84077449999999998020427938172360882163047790527343750'
So the default formatter, rounding to 6 decimals, correctly rounds that value to 0.840774.
0.8407755 on the other hand is:
>>> '%.53f' % 0.8407755
'0.84077550000000000895994389793486334383487701416015625'
and should thus be rounded up.
See The Floating Point Guide for a good introduction as to why that is. (Summary: floating point numbers are represented by the sum of binary fractions).
As per this table here, by default %f will have only 6 digit precision. So, the data is rounded off to 6 digits after the decimal point.
Quoting from the notes section of that table
The alternate form causes the result to always contain a decimal
point, even if no digits follow it.
The precision determines the number of digits after the decimal point
and defaults to 6.

how to change 39.54484700000000 to 39.54 and using python [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
python limiting floats to two decimal points
i want to set 39.54484700000000 to 39.54 using python ,
how to get it ,
thanks
If you want to change the actual value, use round as Eli suggested. However for many values and certain versions of Python this will not result be represented as the string "39.54". If you want to just round it to produce a string to display to the user, you can do
>>> print "%.2f" % (39.54484700000000)
39.54
or in newer versions of Python
>>> print("{:.2f}".format(39.54484700000000))
39.54
or with the fstrings
>>> print(f'{39.54484700000000:.2f}')
39.54
Relevant Documentation: String Formatting Operations, Built-in Functions: round
How about round
>>> import decimal
>>> d=decimal.Decimal("39.54484700000000")
>>> round(d,2)
39.54
You can use the quantize method if you're using a Decimal:
In [24]: q = Decimal('0.00')
In [25]: d = Decimal("115.79341800000000")
In [26]: d.quantize(q)
Out[26]: Decimal("115.79")
>>> round(39.54484700000000, 2)
39.54
Note, however, that the result isn't actually 39.54, but 39.53999999999999914734871708787977695465087890625.
Use round:
Return the floating point value x
rounded to n digits after the decimal
point. If n is omitted, it defaults to
zero. The result is a floating point
number.
Values are rounded to the closest
multiple of 10 to the power minus n;
if two multiples are equally close,
rounding is done away from 0
>>> round(39.544847, 2)
39.539999999999999
>>>
Note that since 39.54 isn't exactly represantable with floating points on my PC (x86), the result is an epsilon off. But that makes no difference (and is a whole different issue with many SO questions and answers on it). If you convert it to a string properly, you'll see what you expect:
>>> "%.2f" % round(39.544847, 2)
'39.54'
Eli mentions using the round function -- depending on your requirements, you may want to return a Decimal object instead.
>>> from decimal import Decimal
>>> float_val = 39.54484700000000
>>> decimal_val = Decimal("%.2f" % float_val)
>>> print decimal_val
39.54
Using Decimal objects lets you specify the exact number of decimal places that you want to keep track of, so you avoid ending up with a floating point number that is represented as 39.539999999999999. Specifically, if you are doing financial calculations, you will almost always be advised to stay away from floating-point numbers.
You can't cast floats directly into Decimals, however (the floats are imprecise, and Python can't guess how you want them rounded,) so I will almost always convert them to a rounded string representation first (that's the "%.2f" % float_val -- %.2f means to display only two decimals, and then create a Decimal out of that.

Categories