Can anyone explain how the modulo operator works in Python?
I cannot understand why 3.5 % 0.1 = 0.1
.
相关问题
- how to define constructor for Python's new Nam
- streaming md5sum of contents of a large remote tar
- How to get the background from multiple images by
- Evil ctypes hack in python
- Correctly parse PDF paragraphs with Python
Modulo gives you the
rest
of a division.3.5
divided by0.1
should give you35
with a rest of0
. But since floats are based on powers of two the numbers are not exact and you get rounding errors.If you need your division of decimal numbers to be exact use the decimal module:
As I am being bashed that my answer is misleading here comes the whole story:
0.1
is slightly bigger than0.1
If you divide the float
3.5
by such number you get a rest of almost0.1
.Let's start with the number
0.11
and continue adding zeros in between the two1
digits in order to make it smaller while keeping it larger than0.1
.The last line gives the impression that we finally have reached
0.1
but changing the format strings reveals the true nature:The default float format of python simply does not show enough precision so that the
3.5 % 0.1 = 0.1
and3.5 % 0.1 = 35.0
. It really is3.5 % 0.100000... = 0.999999...
and3.5 / 0.100000... = 34.999999....
. In case of the division you even end up with the exact result as34.9999...
is ultimatively rounded up to35.0
.Fun fact: If you use a number that is slightly smaller than
0.1
and perform the same operation you end up with a number that is slightly larger than0
:Using C++ you can even show that
3.5
divided by the float0.1
is not35
but something a little smaller.http://ideone.com/fTNVho
In Python
3.5 / 0.1
gives you the exact result of35
because the rounding errors cancel out each other. It really is3.5 / 0.100000... = 34.9999999...
. And34.9999...
is ultimatively so long that you end up with exactly35
. The C++ program shows this nicely as you can mix double and float and play with the precisions of the floating point numbers.Actually, it's not true that
3.5 % 0.1
is0.1
. You can test this very easily:In actuality, on most systems,
3.5 % 0.1
is0.099999999999999811
. But, on some versions of Python,str(0.099999999999999811)
is0.1
:Now, you're probably wondering why
3.5 % 0.1
is0.099999999999999811
instead of0.0
. That's because of the usual floating point rounding issues. If you haven't read What Every Computer Scientist Should Know About Floating-Point Arithmetic, you should—or at least the brief Wikipedia summary of this particular issue.Note also that
3.5/0.1
is not34
, it's35
. So,3.5/0.1 * 0.1 + 3.5%0.1
is3.5999999999999996
, which isn't even close to3.5
. This is pretty much fundamental to the definition of modulus, and it's wrong in Python, and just about every other programming language.But Python 3 comes to the rescue there. Most people who know about
//
know that it's how you do "integer division" between integers, but don't realize that it's how you do modulus-compatible division between any types.3.5//0.1
is34.0
, so3.5//0.1 * 0.1 + 3.5%0.1
is (at least within a small rounding error of)3.5
. This has been backported to 2.x, so (depending on your exact version and platform) you may be able to rely on this. And, if not, you can usedivmod(3.5, 0.1)
, which returns (within rounding error)(34.0, 0.09999999999999981)
all the way back into the mists of time. Of course you still expected this to be(35.0, 0.0)
, not(34.0, almost-0.1)
, but you can't have that because of rounding errors.If you're looking for a quick fix, consider using the
Decimal
type:This isn't a magical panacea — for example, you'll still have to deal with rounding error whenever the exact value of an operation isn't finitely representable in base 10 - but the rounding errors line up better with the cases human intuition expects to be problematic. (There are also advantages to
Decimal
overfloat
in that you can specify explicit precisions, track significant digits, etc., and in that it's actually the same in all Python versions from 2.4 to 3.3, while details aboutfloat
have changed twice in the same time. It's just that it's not perfect, because that would be impossible.) But when you know in advance that your numbers are all exactly representable in base 10, and they don't need more digits than the precision you've configured, it will work.It has to do with the inexact nature of floating point arithmetic.
3.5 % 0.1
gets me0.099999999999999811
, so Python is thinking that 0.1 divides into 3.5 at most 34 times, with 0.099999999999999811 left over. I'm not sure exactly what algorithm is being used to achieve this result, but that's the gist.