In C++ the sqrt
function operates only with double
values.
If we use integers (unsigned long long) can we be sure that
x == sqrt(x * x)
for any positive x
where x * x <= MAXIMUM_VALUE
?
Is it depend on the machine architecture and compiler?
Math. sqrt() method returns a double value which is the square root of the given value and is a correctly rounded positive number. If the argument is NaN and negative number (or negative infinity) Math. sqrt() method returns NaN i.e. Not a Number.
If an integer has square-root, then the last digit is either 0 (even number of zeros) or 1 or 9 ( and the tenth digit must be even) or 4 or 6 ( and the number consisting of the last two digits is divisible by 4) or 5 (and the tenth digit must be 2).
Which is the same thing as saying if positive integer n has a square root, the root is either integer or irrational. But we have not actually proven that positive integer n actually has any square root at all.
Introduction For a natural number x (i.e. x ∈ {0,1,2,3,...}), the integer square root of x is defined as the natural number r such that r2 ≤ x < ( r + 1) 2. It is the greatest r such that r2 ≤ x, or equivalently, the least r such that ( r + 1) 2 > x.
A generalisation of Euclid's lemma states that if n divides a b and n is coprime to a, then n divides b. Using this lemma, it is easy to prove directly that if x is rational and x 2 is an integer, then x is an integer. Suppose that ( p q) 2 = m, where p and q are coprime. Then p 2 = m q 2, so q divides p 2.
But the only positive integer without prime factors is 1 so b = 1 and n = a 2 so n = a. So either for any integer either n is a perfect square with an integer square root, or n does not have a rational square root.
In Java, Math.sqrt(x)
takes a double value. You stated that x is such that x * x
is below Integer.MAX_VALUE
. Every integer is perfectly representable in double - double
in java is explicitly defined as an iEEE-754 style double with a 52-bit mantissa; therefore in java a double
can perfectly represent all integral values between -2^52 and +2^52, which easily covers all int
values (as that is defined as signed 32-bit on java), but it does not cover all long
values. (Defined as signed 64-bit; 64 is more than 52, so no go).
Thus, x * x
loses no precision when it ends up getting converted from int
to double
. Then, Math.sqrt()
on this number will give a result that is also perfectly representable as a double
(because it is x
, and given that x*x
fits in an int
, x
must also fit), and thus, yes, this will always work out for all x
.
But, hey, why not give it a shot, right?
public static void main(String[] args) {
int i = 1;
while (true) {
if (i * i < 0) break;
int j = (int) Math.sqrt(i * i);
if (i != j) System.out.println("Oh dear! " + i + " -> " + j);
i++;
}
System.out.println("Done at " + i);
}
> Done at 46341
Thus proving it by exhaustively trying it all.
Turns out, none exist - any long
value such that x * x
still fits (thus, is <2^63-1
) has the property that x == (long) Math.sqrt(x * x);
. This is presumably because at x*x
, the number fits perfectly in a long, even if not all integer numbers that are this large do. Proof:
long p = 2000000000L;
for (; true; p++) {
long pp = p * p;
if (pp < 0) break;
long q = (long) Math.sqrt(pp);
if (q != p) System.out.println("PROBLEM: " + p + " -> " + q);
}
System.out.println("Abort: " + p);
> Abort: 3037000500
Surely if any number exists that doesn't hold, there is at least one in this high end range. Starting from 0 takes very long.
But do we know that sqrt will always return an exact value for a perfect square, or might it be slightly inaccurate?
We should - it's java. Unlike C, almost everything is 'well defined', and a JVM cannot legally call itself one if it fails to produce the exact answer as specified. The leeway that the Math.sqrt
docs provide is not sufficient for any answer other than precisely x
to be a legal implementation, therefore, yes, this is a guarantee.
In theory the JVM has some very minor leeway with floating point numbers, which strictfp
disables, but [A] that's more about using 80-bit registers to represent numbers instead of 64, which cannot possibly ruin this hypothesis, and [B] a while back a java
tag question showed up to show strictfp
having any effect on any hardware and any VM version and the only viable result was a non-reproducible thing from 15 years ago. I feel quite confident to state that this will always hold, regardless of hardware or VM version.
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