Note: I'm already using decimal.Decimal
What is the best way to perform and display calculations to the end user when you are required to output in the following rough style:
Item - £ 70.10
Item - £ 5.67
Item - £ 10.33
--------------
Total £ 86.10
I was always taught in maths as a kid to not round before your final answer, else you'll lose precision, but in this case if you don't it looks like we have calculation errors. as the calculation behind the display is not the same as the user would do from the numbers displayed to them.
EG:
My app will be doing: 70.1034 + 5.6693 + 10.333333333 = 86.1060333 (86.11 2dp)
My end user will be doing as above: 70.10 + 5.67 + 10.33 = 86.10
Therefore i appear to be incorrect. What is the best way to overcome this? (I mean generally, but python specific methods will help too)
Use the decimal module to get math that works out correctly. You can set it so each value will automatically use two decimal places.
>>> decimal.getcontext().prec = 2
>>> decimal.Decimal(1)/decimal.Decimal(3)
Decimal('0.33')
When you're working with money, it's normal to lose precision at each intermediate calculation.
Related
I am doing a project where I have to print a pay summary for someone based off of information like their hours worked and their pay rate, etc. In the print summary, the spacing is very specific to keep the calculations right-aligned under their specified title (except Premium is centered) so I have been using string formatting to input the variables to keep the formatting consistent between test cases. However, there are some variables that require additional formatting, and I was told that I can not have nested braces.
Here is how I coded the formatting:
print(formatted_work_date + '{:>15}'.format(float(hours_worked)) + ' ' + '{:^7}'.format(user_input_line_2_list[1]) + '{:>11}'.format(str(empl_hourly_payrate)) + '{:>16}'.format(str(round(gross_pay, 2))))
And this is the output:
Workdate Hours Premium Rate Gross Pay
12/23/2020 13.3 0% 71.45 950.29
SO the spacing is correct however, the variable hours_worked is supposed to be a float with 2 digits after the decimal(13.30 not just 13.3), so to get the additional zero I had written '{:.2f}'.format(float(hours_worked)), and I don't know how to place those braces into the braces to format it. Hopefully this question makes sense!
Use the format '{:>15.2f}' to specify that the field width is right-aligned ('>'), 15 characters ('15'), and it's formatted as a float with 2 decimal places (.2f).
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.
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]
'
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..
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