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.