views:

205

answers:

4
>>> num = 4.123456
>>> round(num, 3) # expecting 4.123
4.1230000000000002

I'm expecting 4.123 as a result, Am I wrong?

+6  A: 

This is not a mistake. You need to read What Every computer Scientist Should Know About Floating Point Arithmetic:

http://docs.sun.com/source/806-3568/ncg_goldberg.html

ptomato
+5  A: 

Yep, your expectations don't match the design intent of your tools.

Check out this section of the Python tutorial.


Using math.round is actually pretty rare. if you're trying to display a number as a string to a certain precision, you might want something more like

>>> num = 4.123456
>>> print "%.3f" % num
4.123

You might be interested in the documentation on string formatting.

Mike Graham
I'm finding the canon floating point page over-linked. The link you gave in Python docs is way more practical, and on a level most people can understand and appreciate.
Xavier Ho
Both are valuable resources. I agree this one is a lot better for beginners, but eventually people will want to read the Goldberg article as well.
Joren
Thanks. But I just want to get that as a number, not string.
pocoa
@pocoa, What is wrong with `4.1230000000000002`? If you think `decimal.Decimal` is the answer, you are most likely not understanding the situation well enough.
Mike Graham
@Mike, maybe you're right. I just wanted to store the first 3 digits. I could have the same effect with doing string formatting when displaying it. I was just confused.
pocoa
A: 

If you want to have an exact representation of your floating point number, you have to use decimal.

Felix Kling
Decimal is in general no more exact than binary floating point. It can represent *decimal* fractions exactly (up to a point), which is of course the entire point of the data type, but it also has its limitations.
Joren
`decimal.Decimal` has both representation and roundoff errors, just like `float`, though you can control them some additional ways. I have yet to see a case where someone's problem of float inexactness had the best solution of using `Decimal` instead. `Decimal` is mostly useful in niche financial applications.
Mike Graham
@Joren: *Compared to the built-in float implementation of binary floating point, the new class is especially helpful for financial applications and other uses which require **exact decimal representation**, control over precision, control over rounding to meet legal or regulatory requirements, tracking of significant decimal places, or for applications where the user expects the results to match calculations done by hand.* from [this book](http://www.network-theory.co.uk/docs/pytut/DecimalFloatingPointArithmetic.html). Maybe my answer is not well phrased but this is what I meant.
Felix Kling
"Exact decimal representations" (which slightly oversells `decimal.Decimal` to start with) is a lot different than "*exact* floating point numbers". The key phrase in that quote is "helpful for financial applications".
Mike Graham
@Felix: What Mike says. For what it's worth, that downvote wasn't mine, I think your suggestion can be helpful for dealing with the OP's problem. But I needed to remark that 'exact floating point' is misleading. Decimal floating point will not represent, for example, 1/3 exactly. For that you'd need to have ternary floating point. There is an infinite amount of other fractions decimal floating point can't represent exactly.
Joren
@Joren: Ok. I have to confess I am not that much into floating point numbers so my wording was probably wrong. Sorry for that. Anyway, as you said, this module might help the OP with his problem.
Felix Kling
An accepted negative answer.. now I've seen everything.
bobobobo
+4  A: 

Why do you care? (That's a serious question.)

The answer that you're getting is so close to 4.123 as to make no difference. It can't be exactly 4.123, since there are only finitely many numbers (around 2**64 on a typical machine) that Python can represent exactly, and without going into detail about floating-point representations, it just so happens that 4.123 isn't one of those numbers. By the way, 4.1230000000000002 isn't one of the numbers that can be exactly represented, either; the actual number stored is 4.12300000000000022026824808563105762004852294921875, but Python truncates the decimal representation to 17 significant digits for display purposes. So:

  1. If you're doing mathematics with the result, then the difference between 4.123 and what you're getting is so tiny as to make no real difference. Just don't worry about it.
  2. If you just care about the output looking pretty (i.e., what you're after here is a string rather than a number) then use str, or string formatting.
  3. In the unlikely case that the difference really does matter, e.g., because you're doing financial work and this affects the direction that something rounds later on, use the decimal module.

Final note: In Python 3.x and Python 2.7, the repr of a float has changed so that you will actually get 4.123 as you expect here.

Mark Dickinson
+1, "If you're doing mathematics with the result, then the difference between `4.123` and what you're getting is so tiny as to make no real difference." <--- exactly
Mike Graham
Yes, you're right. Thank you guys for making me understand/remember that.
pocoa