3

Consider the following code snippet in Python:

m = int(math.sqrt(n))

For n = 25, it should give m = 5 (and it does in my shell). But from my C experience I know that using such expression is a bad idea, as sqrt function may return a slightly lower value than the real value, and then after rounding i may get m = 4 instead of m = 5. Is this limitation also involved in python? And if this is the case, what is be the best way to write such expressions in python? What will happen if I use Java or C#? Besides, if there is any inaccuracy, what factors controls the amount of it?

Rafi Kamal
  • 4,262
  • 8
  • 34
  • 47
  • 1
    are you sure that's a python code snippet? It looks like you are trying to typecast, you probably should write it like this: `m = int(math.sqrt(n))`, which is equivalent to what you wrote, but only because `(int)` --> `int` and then you call `int` with the parentheses around the next part of your statement. – Jeff Tratner Aug 13 '12 at 06:56
  • Since we don't have control over `math.sqrt` the only thing you can do is to either write your own implementation of `math.sqrt` or write your own implementation of casting to integer. – freakish Aug 13 '12 at 07:00
  • @JeffTratner Sorry.. I'm new to python. I wrote it as I've done in C.. I'm correcting it. – Rafi Kamal Aug 13 '12 at 07:01
  • 1
    Look up any question on float accuracy. *Any* question, as these problems are entirely language-agnostic, and have very little to do with `sqrt` specifically. –  Aug 13 '12 at 07:03

3 Answers3

7

For proper rounding, use round(); it rounds to the nearest whole number, but returns a float. Then you may construct an int from the result.

(Most probably your code is not performance-critical and you will never notice any slowdown associated with round(). If you do, you probably should be using numpy anyway.)

9000
  • 37,110
  • 8
  • 58
  • 98
  • Note that `round` (as well as `floor`, `ceil`, and `trunc`) gives an int from Py3. – lvc Aug 13 '12 at 07:27
3

If you are very concerned with the accuracy of sqrt, you could use the decimal.Decimal class from the standard library, which provides its own sqrt function. The Decimal class can be set to greater precision than regular Python floats. That said, it may not matter if you are rounding anyways. The Decimal class results in exact numbers (from the docs):

The exactness [of Decimal] carries over into arithmetic. In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.

Jeff Tratner
  • 13,792
  • 4
  • 41
  • 63
  • All the solutions are good but I'm marking is accepted as it points to a generic way from getting over floating point inaccuracy in python. – Rafi Kamal Aug 13 '12 at 07:24
  • 3
    `decimal` is also floating point numbers, and thus also inexact. It is exact **only** for rational numbers whose rendering in base 10 needs at most as much precision as the current context permits. It is not exact (can be made to though) when you need more precision than that, and it is not exact whenever an irrational number enters. Try `sqrt(2)**2` with decimals (spoiler: it is **not** 2 at default precision). The only reason to prefer decimal floating point numbers is that some applications (e.g. finance) have already been doing the same truncation for longer than computers exist. –  Aug 13 '12 at 07:30
  • I actually meant its gives accuracy in such cases when I can't really afford values like 4.999999995 or 5.00000002 :) – Rafi Kamal Aug 13 '12 at 07:47
  • @Rafi That's right, it will give you 4.99999999999999999999999999995 instead. :) – Lauritz V. Thaulow Aug 13 '12 at 07:57
  • 1
    @Rafi From the python help: "Decimal floating point has finite precision with arbitrarily large bounds. The purpose of this module is to support arithmetic using familiar schoolhouse rules and to avoid some of the tricky representation issues associated with binary floating point." The main advantage, in my opinion, is user definable precision and bounds. – Stefano M Aug 13 '12 at 08:22
  • Decimal is quite useful for financial calculations. For scientific / physical, much less so. – 9000 Aug 13 '12 at 12:17
1

The solution is easy. If you're expecting an integer result, use int(math.sqrt(n)+.1). If the value is a little more or less than the integer result, it will round to the correct value.

Codie CodeMonkey
  • 6,899
  • 2
  • 25
  • 43
  • @warwaruk Ooops, sorry missed the dot in `.1`. Yeah, this might work. – freakish Aug 13 '12 at 07:01
  • @delnan: Not a hack at all, acknowledging that floating point math is inaccurate and compensating appropriately is key to numerical methods. If one didn't do this there'd be threshold problems near the theoretical value. This code just says that we expect the result to be correct to +/- .1. – Codie CodeMonkey Aug 13 '12 at 07:06
  • I'm not saying it isn't working, and know fully well why it works. I'm saying it is an inelegant workaround to the inaccuracy of floating point values (and may also fail -- namely for *very* large values -- though that doesn't matter much) and I'd prefer a more elegant solution - such as not using floating point numbers in a context that requires more precision than they offer. –  Aug 13 '12 at 07:17