If you take a number, take its square root, drop the decimal, and then raise it to the second power, the result should always be less than or equal to the original number.
This seems to hold true in python until you try it on 99999999999999975425
for some reason.
import math
def check(n):
assert math.pow(math.floor(math.sqrt(n)), 2) <= n
check(99999999999999975424) # No exception.
check(99999999999999975425) # Throws AssertionError.
It looks like math.pow(math.floor(math.sqrt(99999999999999975425)), 2)
returns 1e+20
.
I assume this has something to do with the way we store values in python... something related to floating point arithmetic, but I can't reason about specifically how that affects this case.
pow(double a) method accepts one argument of the double data type and returns a value which is the square root of the argument. where a is the number whose square root is to be found. Let us see a program where we find the square root of number using the Math. sqrt() method.
Math. sqrt() returns the square root of a value of type double passed to it as argument. If the argument is NaN or negative, then the result is NaN.
The sqrt function returns a double value (for natural reasons which I'm sure that you understand). This value is typically represented in 8 bytes, in floating-point format (as specified by the standard). It doesn't have decimal digits in the way that you see them.
The Math. sqrt() method returns the square root of a number.
The problem is not really about sqrt
or pow
, the problem is you're using numbers larger than floating point can represent precisely. Standard IEEE 64 bit floating point arithmetic can't represent every integer value beyond 52 bits (plus one sign bit).
Try just converting your inputs to float
and back again:
>>> int(float(99999999999999975424))
99999999999999967232
>>> int(float(99999999999999975425))
99999999999999983616
As you can see, the representable value skipped by 16384. The first step in math.sqrt
is converting to float
(C double
), and at that moment, your value increased by enough to ruin the end result.
Short version: float
can't represent large integers precisely. Use decimal
if you need greater precision.
Unlike Evan Rose's (now-deleted) answer claims, this is not due to an epsilon value in the sqrt algorithm.
Most math
module functions cast their inputs to float
, and math.sqrt
is one of them.
99999999999999975425
cannot be represented as a float. For this input, the cast produces a float with exact numeric value 99999999999999983616, which repr
shows as 9.999999999999998e+19
:
>>> float(99999999999999975425)
9.999999999999998e+19
>>> int(_)
99999999999999983616L
The closest float to the square root of this number is 10000000000.0
, and that's what math.sqrt
returns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With