3

I know that I can find the square root of an expression using math.sqrt(x).

I also know that I can find the square root using x**0.5.

But why both? Isn't this non-pythonic? What is the use of math.sqrt() when we can just raise it to the 0.5th power?

defunct-user
  • 183
  • 1
  • 11

2 Answers2

5

This has apparently been discussed half to death on stack overflow already. Here's a summary of the most interesting bits:

Which is faster?

Conclusion: math.sqrt is significantly faster in most Python versions/implementations.

Which is more accurate?

Conclusion: neither, they're both equally (to a rather remarkable level of precision) bad in slightly different ways.

Edit:

For reasons discussed by @MarkDickinson in the comments below, the information in the "Which is more accurate" question linked above is not accurate and is out of date. Which makes sense since it's almost 10 years old.

I can confirm that the tests listed in the accepted answer now return different answers:

    (8885558**0.5)**2: 8885558.000000002
math.sqrt(8885558)**2: 8885558.000000002

                2**1023.99999999999: 1.7976931348498497e+308
(math.sqrt(2**1023.99999999999))**2: 1.7976931348498495e+308
    ((2**1023.99999999999)**0.5)**2: 1.7976931348498495e+308

    ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999: -1.99584030953472e+292
(math.sqrt(2**1023.99999999999))**2 - 2**1023.99999999999: -1.99584030953472e+292

Try the tests out for yourself online. I got the same results on the online interpreter as I did on a couple of my lab machines (which are admittedly all x86-64).

The word of god (ie Guido)

Guido (the benevolent dictator for life of Python) responded to an email sent by the OP of the "which is faster" question:

pow and ** are equivalent; math.sqrt doesn't work for complex numbers, and links to the C sqrt() function. As to which one is faster, I have no idea...

Though he doesn't directly address the reasons for the duplication, he clearly is aware of it, and points out that at least in certain cases they do have different behavior.

Community
  • 1
  • 1
tel
  • 13,005
  • 2
  • 44
  • 62
  • 2
    The "more accurate" answer you link to is deeply flawed. On mainstream machines, it's reasonable to expect the `sqrt` function to end up using the processor's `sqrt` (e.g., `SQRTSD` on x86-64 machines with SSE2), which is likely to be correctly rounded. It would be quite surprising to find cases where `sqrt` is less accurate than `x**0.5`, and not at all surprising to find cases where the opposite is true. In short, on a typical machine, `sqrt` will be at least as accurate as `x**0.5`, and is quite likely to be more accurate for some cases. – Mark Dickinson Mar 29 '18 at 18:11
  • @MarkDickinson ¯\_(ツ)_/¯ Could be, the question is almost ten years old. I'll try out the tests they listed on a couple of machines and post the results. – tel Mar 29 '18 at 18:33
  • As pointed out in the comments to that question, the tests don't actually make any sense for the purposes of figuring out what's more accurate. For that, you need to compare the output of `math.sqrt(x)` with the _true_ square root of `x`, perhaps computed using some high-precision floating-point package. Then do the same for `x**0.5`, for the same values of `x`. I just did that on my machine (a late 2013 MacBook Pro): out of 1000000 randomly generated floats, there were 1413 for which `sqrt(x)` and `x**0.5` differed; `sqrt(x)` was more accurate in every case. – Mark Dickinson Mar 29 '18 at 18:37
  • To be fair, I cheated a _little_ bit, and didn't use a high-precision floating-point package: if `x` is a float, `y` is the float result of `sqrt(x)`, and `z` is the _true_ square root (which will usually _not_ be exactly representable as a float), what we want is the error `y - z`. That's equal to `(y*y - z*z) / (y + z)`, which is equal to `(y*y - x) / (y + z)`, which should be *very close* to `(y*y - x) / 2y`. The latter quantity can be computed exactly using `fractions.Fraction`. That's not quite rigorous, because of the "very close" above. – Mark Dickinson Mar 29 '18 at 18:45
  • Nice work. You could also write that second-to-last term as `(y*y - x) / (2y + d)`, where `d = z - y`. Given that `y` is large, `2y >> d`, and `d` would basically vanish, giving you your last term. It's an approximation that would definitely pass muster in my field (physics), though I can't help but feel like there's still a potential FP-specific pitfall in there someplace. – tel Mar 29 '18 at 19:46
  • Your more rigorous plan sounds like it would be a nice (and possibly somewhat involved) research project for someone. – tel Mar 29 '18 at 19:47
0

I wouldn't think too much about this. sqrt is just a simplification if raising to 1/2; some python programmers may not know this and it's more idiomatic in my eyes.

Brandon Mowat
  • 374
  • 1
  • 8