Let's consider the code below
code:
#!/usr/bin/env python
class Foo():
def __init__(self, b):
self.a = 0.0
self.b = b
def count_a(self):
self.a += 0.1
foo = Foo(1)
for i in range(0, 15):
foo.count_a()
print "a =", foo.a, "b =", foo.b, '"a == b" ->', foo.a == foo.b
Output:
a = 0.2 b = 1 "a == b" -> False
a = 0.4 b = 1 "a == b" -> False
a = 0.6 b = 1 "a == b" -> False
a = 0.8 b = 1 "a == b" -> False
a = 1.0 b = 1 "a == b" -> True
a = 1.2 b = 1 "a == b" -> False
a = 1.4 b = 1 "a == b" -> False
a = 1.6 b = 1 "a == b" -> False
a = 1.8 b = 1 "a == b" -> False
a = 2.0 b = 1 "a == b" -> False
a = 2.2 b = 1 "a == b" -> False
a = 2.4 b = 1 "a == b" -> False
a = 2.6 b = 1 "a == b" -> False
a = 2.8 b = 1 "a == b" -> False
a = 3.0 b = 1 "a == b" -> False
But if I change code on line 11
to foo = Foo(2)
, the output is turned to be:
a = 0.2 b = 2 "a == b" -> False
a = 0.4 b = 2 "a == b" -> False
a = 0.6 b = 2 "a == b" -> False
a = 0.8 b = 2 "a == b" -> False
a = 1.0 b = 2 "a == b" -> False
a = 1.2 b = 2 "a == b" -> False
a = 1.4 b = 2 "a == b" -> False
a = 1.6 b = 2 "a == b" -> False
a = 1.8 b = 2 "a == b" -> False
a = 2.0 b = 2 "a == b" -> False *
a = 2.2 b = 2 "a == b" -> False
a = 2.4 b = 2 "a == b" -> False
a = 2.6 b = 2 "a == b" -> False
a = 2.8 b = 2 "a == b" -> False
a = 3.0 b = 2 "a == b" -> False
You will see that the output a = 2.0 b = 2 "a == b" -> False
is totally weird. I think I might misunderstand some concept of OOP in Python. Please explain to me why this unexpected output is happened and how to solve this problem.
This has nothing to do with Object Orientation - it has to do with the way computers represent floating point numbers internally, and rounding errors. http://floating-point-gui.de/basic/
The Python specificity here is the default string representation of floating point numbers, which will round them at less decimal places than the internal representation for pretty printing.
Although, for people needing correct comparisons, respecting the scale of floating point numbers, Python has introduced a nice mechanism with PEP 485, which added the math.isclose
function to the standard library.