I am trying to add fractions together (1/5 and such), and since binary is unable to add certain fractions, I'm getting really horrible answers like 2.99999999999996 and so on. I understand I can use math.round (since pythons round is not actually round) to get it to 3, but I don't want that.
Is there any module I can use to add two numbers together (such as 0.2 and 0.2) and get a result of something other then 0.39999999999999999999999996?
EDIT:
I tried using decimal, the result I got from this after inputting 6, 12, 24 and 24 is 2.9999999999:
while True:
try:
x += 1
print("\n" + "Enter resistance of resistor " + str(x))
resistors.append(int(input()))
except:
temp = Decimal(0)
print(temp)
for i in resistors:
print(temp)
temp += Decimal(1)/Decimal(i)
temp = temp**-1
print("\n" + "The total resistance of inputted resistors in parallel is: " + str(temp))
input()
break
It's not "binary incompetence". It is a result of using real machines to represent idealized mathematical entities. There are an infinite number of real numbers between 0 and 1. Whatever representation you use, binary, ternary, octal, decimal or hex, if you have only a finite number of digits, then some of those real numbers are going to have to share the same representation. You can't represent 1/100 accurately in binary because it is a recurring binary fraction. Just as you can't represent 1/3 in decimal because it is a recurring decimal fraction. But when your 4-function pocket calculator shows 1/3 as 0.3333333 you don't call that decimal incompetence.
If you want to represent rational numbers accurately then you can use the fractions module:
>>> import fractions
>>> fifth = fractions.Fraction(1,5)
>>> fifth * 2
Fraction(2, 5)
But when you convert Fraction(2,5) to a float, you go back to floating point representation.
I think that not is the real issue, though. I think you just need to fix this line:
print("\n" + "The total resistance of inputted resistors in parallel is: " + str(temp))
That is giving you the default string representation of the number, which shows the closest possible representation to the highest possible precision. But you actually want to see a nice number:
print("\n" + "The total resistance of inputted resistors in parallel is: %g" % temp)
Related
I'd like to calculate up to 20 decimal places.
the answer I want 0.60000000000000000000
My answer 0.59999999999999997780
How do I solve this?
my code
a,b=map(float,input().split())
print("%.20f"%(a/b))
print('{:<020}'.format(0.6));
use format , and right padding
print('{:<020}'.format(a/b));
So for your case you can use :
from decimal import *
getcontext().prec = 20
result = ("{:.20f}".format(Decimal("0.6")))
print(result)
or
result=5/4 #add a/b here
formatedResult = ('{:<0'+str((len(str(float(result)).split('.')[0])+21))+'}').format(float(result))
print("The formated result: " + formatedResult)
print("Length of digit after decimal point: "+str(len(formatedResult.split('.')[1])))
Here we find number of characters before the decimal point and add 21 to it (including the decimal character)
If I tell Python v. 3.4.3, round(2.5), then it outputs 2. If I tell it round(1.5) then it outputs 2 as well, though. Similarly, round(3.5) gives 4, while round(4.5) gives 4 as well. I need Python to round with consistency, though. Specifically, it needs to round anytime I input a number halfway between two integers. So round(1.5) = 1 and round(2.5) = 2, while round(1.6) = 2 and such, as usual.
How can I resolve this?
EDIT: I've already read the documentation for the round function and understand that this is its intended behavior. My question is, how can I alter this behavior, because for my purposes I need 1.5 round down.
Python 3 uses a different rounding behaviour compared to Python 2: it now uses so-called "banker's rounding" (Wikipedia): when the integer part is odd, the number is rounded away from zero; when the integer part is even, is it rounded towards zero.
The reason for this is to avoid a bias, when all values at .5 are rounded away from zero (and then e.g. summed).
This is the behaviour you are seeing, and it is in fact consistent. It's perhaps just different than what you are used to.
The round docs do address the peculiaries of rounding floating point numbers.
You can use the decimal library to achieve what you want.
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_DOWN
round(2.675, 2)
# output: 2.67
Decimal('2.675').quantize(Decimal('1.11'), rounding=ROUND_HALF_UP)
# output: 2.68
Decimal('2.5').quantize(Decimal('1.'), rounding=ROUND_HALF_DOWN)
# output: 2
Your want "round down", and you are getting "round to even". Just do it manually by doing
ceil(x - 0.5)
This is documented pretty well. According to the Python docs for round:
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information
In specific, this is a side-effect of how computers handle floating-point numbers in general.
If you need more precision, including different rounding, I suggest you check out the Python Decimal module. Specifically of interest, they have the ability to control rounding modes. Looks like you might want decimal.ROUND_HALF_DOWN.
Python 3 provides rounding methods defined in the IEEE Standard for Floating-Point Arithmetic (IEEE 754), the default rounding[1] is directed to the nearest number and minimizing cumulative errors.
In IEEE 754, there are 5 methods defined, two for rounding to nearest (Python provides the first one by round) and three methods that are explicitly directed (Python has trunc, ceil, and floor in its Math module).
You obviously need a directed rounding and there is a way to tell this Python, you have just to choose.
[1] Since the representation of floating point numbers in computers is limited, rounding is not as trivial as you might think, you'll be surprised! I recommend a careful read of 15. Floating Point Arithmetic: Issues and Limitations in the python 3 documentation.
I believe I have the answer to all the rounding errors people have been encountering. I have wrote my own method, which functions same as the "round" but actually looks at the last digit and rounds from there case by case. There is no converting a decimal to binary. It can handle any amount of numbers behind the decimal and it also takes scientific notation (as outputted by floats). It also doesn't require any imports! Let me know if you catch any cases that don't work!
def Round(Number,digits = 0):
Number_Str = str(Number)
if "e" in Number_Str:
Number_Str = "%.10f" % float(Number_Str)
if "." in Number_Str: #If not given an integer
try:
Number_List = list(Number_Str) #All the characters in Number in a list
Number_To_Check = Number_List[Number_List.index(".") + 1 + digits] #Gets value to be looked at for rounding.
if int(Number_To_Check) >= 5:
Index_Number_To_Round = Number_List.index(".") + digits
if Number_List[Index_Number_To_Round] == ".":
Index_Number_To_Round -= 1
if int(Number_List[Index_Number_To_Round]) == 9:
Number_List_Spliced = Number_List[:Number_List.index(".")+digits]
for index in range(-1,-len(Number_List_Spliced) - 1,-1):
if Number_List_Spliced[index] == ".":
continue
elif int(Number_List_Spliced[index]) == 9:
Number_List_Spliced[index] = "0"
try:
Number_List_Spliced[index-1]
continue
except IndexError:
Number_List_Spliced.insert(0,"1")
else:
Number_List_Spliced[index] = str(int(Number_List_Spliced[index])+1)
break
FinalNumber = "".join(Number_List_Spliced)
else:
Number_List[Index_Number_To_Round] = str(int(Number_List[Index_Number_To_Round])+1)
FinalNumber = "".join(Number_List[:Index_Number_To_Round + 1])
return float(FinalNumber)
else:
FinalNumber = "".join(Number_List[:Number_List.index(".") + 1 + digits])
return float(FinalNumber)
except IndexError:
return float(Number)
else: #If given an integer
return float(Number)
I'm fairly new to Python, and was wondering how would I be able to control the decimal precision of any given number without using any the decimal module or floating points (eg: " %4f" %n).
Examples (edit):
input(2/7)
0.28571428571....
input(1/3)
0.33333333333333....
and I wanted them to thousand decimal points or any decimal point for that matter. I was thinking of using a while as a controlled loop, but I'm not really sure how to do so. Thanks
edit: The reason why I'm not using the decimal module is just so I can conceptualize the algorithm/logic behind these type of things. Just trying to really understand the logic behind things.
We can use a long to store a decimal with high precision, and do arithmetic on it. Here's how you'd print it out:
def print_decimal(val, prec):
intp, fracp = divmod(val, 10**prec)
print str(intp) + '.' + str(fracp).zfill(prec)
Usage:
>>> prec = 1000
>>> a = 2 * 10**prec
>>> b = a//7
>>> print_decimal(b, prec)
0.2857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857142857
Without the Decimal module (why, though?), assuming Python 3:
def divide(num, den, prec):
a = (num*10**prec) // den
s = str(a).zfill(prec+1)
return s[0:-prec] + "." + s[-prec:]
Thanks to #nneonneo for the clever .zfill() idea!
>>> divide(2,7,1000)
'0.28571428571428571428571428571428571428571428571428571428571428571428571428571
42857142857142857142857142857142857142857142857142857142857142857142857142857142
85714285714285714285714285714285714285714285714285714285714285714285714285714285
71428571428571428571428571428571428571428571428571428571428571428571428571428571
42857142857142857142857142857142857142857142857142857142857142857142857142857142
85714285714285714285714285714285714285714285714285714285714285714285714285714285
71428571428571428571428571428571428571428571428571428571428571428571428571428571
42857142857142857142857142857142857142857142857142857142857142857142857142857142
85714285714285714285714285714285714285714285714285714285714285714285714285714285
71428571428571428571428571428571428571428571428571428571428571428571428571428571
42857142857142857142857142857142857142857142857142857142857142857142857142857142
85714285714285714285714285714285714285714285714285714285714285714285714285714285
7142857142857142857142857142857142857142857'
Caveat: This uses floor division, so divide(2,3,2) will give you 0.66 instead of 0.67.
While the other answers use very large values to handle the precision, this implements long division.
def divide(num, denom, prec=30, return_remainder=False):
"long divison"
remain=lim=0
digits=[]
#whole part
for i in str(num):
d=0;remain*=10
remain+=int(i)
while denom*d<=remain:d+=1
if denom*d>remain:d-=1
remain-=denom*d
digits.append(d)
#fractional part
if remain:digits.append('.')
while remain and lim<prec:
d=0;remain*=10
while denom*d<=remain:d+=1
if denom*d>remain:d-=1
remain-=denom*d
digits.append(d)
lim+=1
#trim leading zeros
while digits[0]==0 and digits[1]!='.':
digits=digits[1:]
quotient = ''.join(list(map(str,digits)))
if return_remainder:
return (quotient, remain)
else:
return quotient
Because it's the division algorithm, every digit will be correct and you can get the remainder (unlike floor division which won't have the remainder). The precision here I've implemented as the number of digits after the decimal sign.
>>> divide(2,7,70)
'0.2857142857142857142857142857142857142857142857142857142857142857142857'
>>> divide(2,7,70,True)
('0.2857142857142857142857142857142857142857142857142857142857142857142857', 1)
The reason I'm asking this is because there is a validation in OpenERP that it's driving me crazy:
>>> round(1.2 / 0.01) * 0.01
1.2
>>> round(12.2 / 0.01) * 0.01
12.200000000000001
>>> round(122.2 / 0.01) * 0.01
122.2
>>> round(1222.2 / 0.01) * 0.01
1222.2
As you can see, the second round is returning an odd value.
Can someone explain to me why is this happening?
This has in fact nothing to with round, you can witness the exact same problem if you just do 1220 * 0.01:
>>> 1220*0.01
12.200000000000001
What you see here is a standard floating point issue.
You might want to read what Wikipedia has to say about floating point accuracy problems:
The fact that floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.
Also see:
Numerical analysis
Numerical stability
A simple example for numerical instability with floating-point:
the numbers are finite. lets say we save 4 digits after the dot in a given computer or language.
0.0001 multiplied with 0.0001 would result something lower than 0.0001, and therefore it is impossible to save this result!
In this case if you calculate (0.0001 x 0.0001) / 0.0001 = 0.0001, this simple computer will fail in being accurate because it tries to multiply first and only afterwards to divide. In javascript, dividing with fractions leads to similar inaccuracies.
The float type that you are using stores binary floating point numbers. Not every decimal number is exactly representable as a float. In particular there is no exact representation of 1.2 or 0.01, so the actual number stored in the computer will differ very slightly from the value written in the source code. This representation error can cause calculations to give slightly different results from the exact mathematical result.
It is important to be aware of the possibility of small errors whenever you use floating point arithmetic, and write your code to work well even when the values calculated are not exactly correct. For example, you should consider rounding values to a certain number of decimal places when displaying them to the user.
You could also consider using the decimal type which stores decimal floating point numbers. If you use decimal then 1.2 can be stored exactly. However, working with decimal will reduce the performance of your code. You should only use it if exact representation of decimal numbers is important. You should also be aware that decimal does not mean that you'll never have any problems. For example 0.33333... has no exact representation as a decimal.
There is a loss of accuracy from the division due to the way floating point numbers are stored, so you see that this identity doesn't hold
>>> 12.2 / 0.01 * 0.01 == 12.2
False
bArmageddon, has provided a bunch of links which you should read, but I believe the takeaway message is don't expect floats to give exact results unless you fully understand the limits of the representation.
Especially don't use floats to represent amounts of money! which is a pretty common mistake
Python also has the decimal module, which may be useful to you
Others have answered your question and mentioned that many numbers don't have an exact binary fractional representation. If you are accustomed to working only with decimal numbers, it can seem deeply weird that a nice, "round" number like 0.01 could be a non-terminating number in some other base. In the spirit of "seeing is believing," here's a little Python program that will print out a binary representation of any number to any desired number of digits.
from decimal import Decimal
n = Decimal("0.01") # the number to print the binary equivalent of
m = 1000 # maximum number of digits to print
p = -1
r = []
w = int(n)
n = abs(n) - abs(w)
while n and -p < m:
s = Decimal(2) ** p
if n >= s:
r.append("1")
n -= s
else:
r.append("0")
p -= 1
print "%s.%s%s" % ("-" if w < 0 else "", bin(abs(w))[2:],
"".join(r), "..." if n else "")
I'm having a problem with modulus on a floating point number in Python. This code:
...
print '(' + repr(olddir) + ' + ' + repr(self.colsize) + ') % (math.pi*2) = ' + repr((olddir+self.colsize)
...
Prints:
(6.281876310240881 + 0.001308996938995747) % (math.pi*2) = 2.9043434324194095e-13
I know floating point numbers aren't precise. But I can't get this to make any sense.
I don't know if it is in any way related but Google Calculator can't handle this calculation either. This is the output from Google Calculator:
(6.28187631024 + 0.001308996939) % (pi * 2) = 6.28318531
What is causing this calculation error? And how can I avoid it in my Python program?
Using str() to print a floating point number actually prints a rounded version of the number:
>>> print repr(math.pi)
3.1415926535897931
>>> print str(math.pi)
3.14159265359
So we can't really reproduce your results, since we don't know the exact values you are doing the computation with. Obviously, the exact value of olddir+self.colsize is slightly greater than 2*math.pi, while the sum of the rounded values you used in Google Calculator is slightly less than 2*math.pi.
The difference between str and repr
>>> import scipy
>>> pi = scipy.pi
>>> str(pi)
'3.14159265359'
>>> repr(pi)
'3.1415926535897931'
str truncates floating point numbers to 12 digits, where repr gives the internal representation (as a string).
EDIT: So in summary, the problem arose because you rounded prematurely and are calculating the modulus of something via a number that's very close to it. With floating point numbers, rounding is inevitably involved in converting decimal numbers into binary.
First, do an example of how rounding hurts you with actual math (not floating point math). Look at (3.14+3.14) % (3.14+3.14), which is obviously zero. Now what would happen if we rounded the digits to one decimal digit first on one side? Well (3.1+3.1) % (3.14+3.14) = 6.2 % (6.28) = 6.2 (what google gave you). Or if you did round(3.14159,5) + round(3.14159,5) % (3.14159 + 3.14159) = 6.2832 % 6.28318 = 2e-5.
So in by rounding to N digits (by using str which effectively rounds the numbers), your calculation is only accurate to less than N digits. To have this work going forward force rounding at some higher digit (keeping two calculated digits for safety) is necessary. E.g., str rounds at digit 12, so maybe we should round at digit 10.
>>> round(6.28187631024 + 0.001308996939,10) % (round(pi * 2,10))
0