Abhilash Mandaliya
Abhilash Mandaliya

Reputation: 159

Why Math.sqrt() outputs wrong value in java?

long mynum = Long.parseLong("7660142319573120");
long ans = (long)Math.sqrt(mynum) // output = 87522239
long ans_ans = ans * ans;

In this case, I am getting ans_ans > mynum where it should be <=mynum. Why such behavior? I tried this with node js as well. There also result is same.

Upvotes: 2

Views: 3603

Answers (5)

IfOnly
IfOnly

Reputation: 540

double ans = (double)Math.sqrt(15);
System.out.println("Double : " + ans);
double ans_ans = ans * ans;
System.out.println("Double : " + ans_ans);

long ans1 = (long)Math.sqrt(15);
System.out.println("Long : " + ans1);
long ans_ans1 = ans1 * ans1;
System.out.println("Long : " + ans_ans1);

Results :

Double : 3.872983346207417
Double : 15.000000000000002
Long : 3
Long : 9

I hope this makes it clear.

Upvotes: 3

Lutz Lehmann
Lutz Lehmann

Reputation: 25992

You do not need the long type, all numbers are representable in double, and Math.sqrt first converts to double then computes the square root via FPU instruction (on a standard PC).

This situation occurs for numbers b=a^2-1 where a is an integer in the range

67108865 <= a <= 94906265

The square root of b has a series expansion starting with

a-1/(2*a)-1/(8*a^2)+... 

If the relative error 1/(2*a^2) falls below the machine epsilon, the closest representable double number is a.

On the other hand for this trick to work one needs that a*a-1.0 is exactly representable in double, which gives the conditions

1/(2*a^2) <mu=2^(-53) < 1/(a^2)

or

2^52 < a^2 < 2^53
2^26+1=67108865 <= a <= floor(sqrt(2)*2^26)=94906265

Upvotes: 1

Thomas B&#246;hm
Thomas B&#246;hm

Reputation: 1486

You are calling Math.sqrt with a long. As the JavaDoc points out, it returns a "correctly rounded value".

Since your square-root is not an non-comma-value (87522238,999999994), your result is rounded up to your output 87522239.

After that, the square of the value is intuitively larger than mynum, since you multiply larger numbers than the root!

Upvotes: 4

Thomas
Thomas

Reputation: 181745

Math.sqrt operates on doubles, not longs, so mynum gets converted to a double first. This is a 64-bits floating point number, which has "15–17 decimal digits of precision" (Wikipedia).

Your input number has 16 digits, so you may be losing precision on the input already. You may also be losing precision on the output.

If you really need an integer square root of long numbers, or generally numbers that are too big for accurate representation as a double, look into integer square root algorithms.

You can also use LongMath.sqrt() from the Guava library.

Upvotes: 5

RetteMich
RetteMich

Reputation: 125

The answer is: rounding. The result of (Long)Math.sqrt(7660142319573120) is 87522239, but the mathematical result is 87522238,999999994287166259537761.... if you multiply the ans value, which is rounded up in order to be stored as a whole number, you will get bigger number than multiplying the exact result.

Upvotes: 2

Related Questions