python small floats rounding to 2 decimals - python

Yes, another one of these, however, I have tried a ton of the available examples and solutions and cannot seem to be able to solve my issue.
I need to measure the performance of an API call and decided to use the following:
for x in range(0, 5):
try:
nf=urllib.urlopen(_url)
_start=time.time()
page=nf.read()
_end=time.time()
nf.close()
_delta=(_end - _start)
_processingTimelist.append(_delta)
time.sleep(1)
except:
_processingTimelist.append(9999)
outcome:
[5.2928924560546875e-05, 4.9114227294921875e-05, 4.887580871582031e-05, 7.510185241699219e-05, 5.1975250244140625e-05]
5.55992126465e-05
So far so good, looks like what I'm after. However now I want to submit this to a monitoring service and want to round it to 2 digits, as these are already representing a super small unit (milliseconds) and sending so many digits is just ridiculous.
I have tried a ton of these rounding methods, but I get super strange results like:
_processingTime = round(_processingTime, 3)
print _processingTime
result:
0.0
OR:
_processingTime = float("{0:.4f}".format(_processingTime))
print _processingTime
result:
0.0001
Why is that, and how to solve?
I don't care too much about precision, however I would expect for example 5.55992126465e-05 to become 5.56, or even 5.55 would be acceptable as the difference in real time units is super negligible.

You can format your number with scientific notation:
>>> '{:.2e}'.format(5.2928924560546875e-05)
'5.29e-05'
You can also convert it back into a float:
>>> float('{:.2e}'.format(5.2928924560546875e-05))
5.29e-05
Or for all your numbers:
>>> numbers = [5.2928924560546875e-05, 4.9114227294921875e-05, 4.887580871582031e-05,
7.510185241699219e-05, 5.1975250244140625e-05]
>>> [float('{:.2e}'.format(x)) for x in numbers]
[5.29e-05, 4.91e-05, 4.89e-05, 7.51e-05, 5.2e-05]
'

Related

How to make python output more decimal places of a recurring decimal?

```python
import decimal
x=[]
#functions etc. x is changed
#now returns is a list full of integers
print(sum(x)/len(x))
#This happens to give 0.6999
print(decimal.Decimal(sum(x)/len(x))
# This happens to give 0.6998999999996034 blah blah blah
```
The decimal module gives too many decimal places and round(decimal.Decimal(x),5) gives 0.69990
I would like it to output 0.69999(5 d.p.) but it outputs 0.6999 or 0.69990
you already have the right answer: round(decimal.Decimal(x),5) which gives 0.69990. In your case, you should not expect 0.69999, it is not even close to 0.699899999999.
The python built-in function round is good to use, but sometimes it can be surprising, see more details here
To summary:
import decimal
x=0.699899999
print("x =", x)
g = round(decimal.Decimal(x),5)
print("rounded:", g)
output:
x = 0.699899999
rounded: 0.69990
You can try something like this
x=0.6999932
g = float("{0:.5f}".format(x))
print(g)
#output be like
0.69999
The number 0.699899999999... is mathematically equivalent to 0.6999000..., assuming the 9s repeat farther than we want to go before we round things off.
This is the same as the question of why 0.9999... is equal to 1 (for which you can find many explanations online, I'm fond of this one myself), just shifted several decimal places to the right. All the 9s at the end turn into a 1. That one gets added to the last 8 and turn it into a 9. That's all followed by infinite zeros, which Python omits by default.

How to divide large numbers with a floating point?

I have some large numbers (like 10000000 digits in total or more). Since I will lose precision, they are stored like strings.
Lets take some 'small' numbers as an example (some numbers also can be integers):
a = 4782916578987656789087654678908765467417657489104.9486718490129876578
b = 657890876566567890.8765467890987654
I want to make some operations on them.
Division. Well, answer is 7.270075858095143e+30
Multiplicaiton: 3.1466371806949598e+66
And so on.
Desirable output is full number as string, but with given precision for floating point with trancated zeros and rest.
Example:
888888888888.23 / 2.5122217 == 353825814373.082590504959329565857965
(24 digits after 'point')`
I've tried decimals module, but it can't handle big integers: class 'decimal.DivisionImpossible and maybe something else what I'm not aware of.
Is there is a way to do it with standard library, or at least numpy. Or maybe some algorithm what I can also reproduce in some other languages like JavaScript?
Note: I know I can make Decimal.getcontext().prec = 8888888888888 or bigger, but it will took more time to calculate, and what if numbers are 1 and 1.7373 do I need to waste resources on it? Also it's precision for whole number, not only 'floating' digits.
The decimal module is your friend here. If you want to go wild, well...
import decimal
from decimal import Decimal
import sys
c = decimal.getcontext()
c.prec = 899_999_768
c.Emax = decimal.MAX_EMAX
c.Emin = decimal.MIN_EMIN
a = Decimal('149846549e500000')
b = Decimal('254984984e449')
d = a / b
f = a * b
Remember that c.prec gives you the number of digits that are shown when you print it. According to the documentation, the maximum number is 999999999999999999, and you are bound to the memory of your computer. In my case (my computer, actually), c.prec is a good number before the computer breaks.
If you print the results, what happens?
print(f'{d}')
print(f'{f}')
Since you want to play with big, big numbers, well, there you have it.
P.S. I am trying to write a number with 10 000 000 digits, but my text editors don't allow that... they freeze.

python/pandas keeping decimal places exactly as in string

I'm new to Python/pandas, and I have an issue with decimals and can't figure out for a few hours already how to solve it. Basically I want to read CSV file into pandas and keep the decimals exactly as they are stored in text, for future comparisons and simple math operations.
Example:
is_string_dtype(report['item_weight_kg'])
Out[12]: True
l = report.loc[report['item'] == 'B0WY']
num1 = l['item_weight_kg'][8210]
num1
Out[14]: '22.000370049504'
then I try to convert them to float, which gives me a value ending in ...3999 instead of ...4
report['item_weight_kg'] = report.apply(lambda x: float(x['item_weight_kg']), axis = 1 )
l = report.loc[report['item'] == 'B0WY']
num1 = l['item_weight_kg'][8210]
num1
Out[17]: 22.000370049503999
right after importing the dataset, I've tried to convert it to float, and in console it works properly, returns me the desired value, but when I am trying to apply it to the whole dataset, it doesn't
float(decimal.Decimal(l['item_weight_kg'][8210]))
Out[23]: 22.000370049504
report['item_weight_kg'] = report.apply(lambda x: float(decimal.Decimal(x['item_weight_kg'])), axis = 1 )
l = report.loc[report['item'] == 'B0WY']
num1 = l['item_weight_kg'][8210]
num1
Out[25]: 22.000370049503999
How can this be solved?
I have some good and bad news for you.
The bad news is that in python:
0.1 + 0.2 will give you 0.30000000000000004
And 0.1 + 0.2 == 0.3 will give False.
This is not just in python. This phenomena occurs in very large number of programming languages. In fact, there is a whole website dedicated to it! : https://0.30000000000000004.com/
You can read more about this in the official python docs, here.
The thing is, dealing with floats is tricky, especially when you try to do exact math (i.e. equality) just like your case.
Never expect exact math when dealing with floats!
Instead, when you try to check to floats for equality, you check if they are very close to each other.
Python 3.5+ provides this functionality (see here), and you can implement one yourself.
A simple float equality comparison goes like this:
epsilon = 0.0000001 # the smallest acceptable precision error
def float_equals(a,b):
return abs(a-b) &lt= epsilon
But what if we want more precision than what standard python offers?
In that case you can use an arbitrary precision library, like mpmath. That's the good news (maybe, idk).
Normally I'd use print formatting for strings or the round function.
https://docs.python.org/3/library/functions.html?highlight=round#round
Because you are using decimal you might meet your requirements by altering precision
https://docs.python.org/3/library/decimal.html?highlight=round

Strict Python formatting for floats

I'm using PYTHON to write to a file where the formatting is very strict. I have 10 available spaces in each column which cannot be exceeded.
I want to write the as many decimals as I can, but if the number is negative, the minus sign must be preferred over the last decimals. Also the period in the float must be counted into the number of available spaces. Numbers should be right trunctated
Example:
Let's say I want to print two numbers
a = 123.4567891011
b = 0.9876543210
Then I would want the result:
123.4567890.98765432
But if I now have the following:
a = -123.1111111111
b = 98765.432101234
c = 567
d = 0.1234
Then I'd want:
-123.1111198765.4321 567.0 0.1234
Would be to nice use exponential notation for high numbers, but not a necessity. I'm unable to find the answer. All I can find is to fix the format to number of significant digits, which really won't help me.
I've tried several methods of the
f.write({0:>10}{1:>10}.format(a,b))
but can't figure it out. Hope you see what I`m looking for.
Okay, so I found a way. I basically convert everything to strings and use:
f.write("{0:>10.10}{1:>10.10}".format(str(a),str(b)))
and so on..

Truncation in python

How can we truncate (not round) the cube root of a given number after the 10th decimal place in python?
For Example:
If number is 8 the required output is 2.0000000000 and for 33076161 it is 321.0000000000
Scale - truncate - unscale:
n = 10.0
cube_root = 1e-10 * int(1e10 * n**(1.0/3.0))
You should only do such truncations (unless you have a serious reason otherwise) while printing out results. There is no exact binary representation in floating point format, for a whole host of everyday decimal values:
print 33076161**(1.0/3.0)
A calculator gives you a different answer than Python gives you. Even Windows calculator does a passable job on cuberoot(33076161), whereas the answer given by python will be minutely incorrect unless you use rounding.
So, the question you ask is fundamentally unanswerable since it assumes capabilities that do not exist in floating point math.
Wrong Answer #1: This actually rounds instead of truncating, but for the cases you specified, it provides the correct output, probably due to rounding compensating for the inherent floating point precision problem you will hit in case #2:
print "%3.10f" % 10**(1.0/3.0)
Wrong Answer #2: But you could truncate (as a string) an 11-digit rounded value, which, as has been pointed out to me, would fail for values very near rollover, and in other strange ways, so DON'T do this:
print ("%3.11f" % 10**(1.0/3.0))[:-1]
Reasonably Close Answer #3: I wrote a little function that is for display only:
import math
def str_truncate(f,d):
s = f*(10.0**(d))
str = `math.trunc(s)`.rstrip('L')
n = len(str)-d
w = str[0:n]
if w=='':
w='0'
ad =str[n:d+n]
return w+'.'+ad
d = 8**(1.0/3.0)
t=str_truncate(d,10)
print 'case 1',t
d = 33076161**(1.0/3.0)
t=str_truncate(d,10)
print 'case 2',t
d = 10000**(1.0/3.0)
t=str_truncate(d,10)
print 'case 3',t
d = 0.1**(1.0/3.0)
t=str_truncate(d,10)
print 'case 4',t
Note that Python fails to perform exactly as per your expectations in case #2 due to your friendly neighborhood floating point precision being non-infinite.
You should maybe know about this document too:
What Every Computer Scientist Should Know About Floating Point
And you might be interested to know that Python has add-ons that provide arbitary precision features that will allow you to calculate the cube root of something to any number of decimals you might want. Using packages like mpmath, you can free yourself from the accuracy limitations of conventional floating point math, but at a considerable cost in performance (speed).
It is interesting to me that the built-in decimal unit does not solve this problem, since 1/3 is a rational (repeating) but non-terminating number in decimal, thus it can't be accurately represented either in decimal notation, nor floating point:
import decimal
third = decimal.Decimal(1)/decimal.Decimal(3)
print decimal.Decimal(33076161)**third # cuberoot using decimal
output:
320.9999999999999999999999998
Update: Sven provided this cool use of Logs which works for this particular case, it outputs the desired 321 value, instead of 320.99999...: Nifty. I love Log(). However this works for 321 cubed, but fails in the case of 320 cubed:
exp(log(33076161)/3)
It seems that fractions doesn't solve this problem, but I wish it did:
import fractions
third = fractions.Fraction(1,3)
def cuberoot(n):
return n ** third
print '%.14f'%cuberoot(33076161)
num = 17**(1.0/3.0)
num = int(num * 100000000000)/100000000000.0
print "%.10f" % num
What about this code .. I have created it for my personal use. although it is so simple, it is working well.
def truncation_machine(original,edge):
'''
Function of the function :) :
it performs truncation operation on long decimal numbers.
Input:
a) the number that needs to undergo truncation.
b) the no. of decimals that we want to KEEP.
Output:
A clean truncated number.
Example: original=1.123456789
edge=4
output=1.1234
'''
import math
g=original*(10**edge)
h=math.trunc(g)
T=h/(10**edge)
print('The original number ('+str(original)+') underwent a '+str(edge)+'-digit truncation to be in the form: '+str(T))
return T

Categories

Resources